home *** CD-ROM | disk | FTP | other *** search
- /* $Filename: WormWars/Source/engine.c
- * $VER: WormWars 7.21
- *
- * © Copyright 1993-2002 James R. Jacobs. Freely distributable.
- */
-
- #include <string.h>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
- #include <assert.h>
- #define ASSERT
-
- #include "stdafx.h"
- #include "diff.h"
- #include "same.h"
-
- #define OTTER_UP 0
- #define OTTER_DOWN 1
- #define OTTER_LEFT 2
- #define OTTER_RIGHT 3
-
- #define ARROWX (FIELDX + 1)
- #define BONUSSPEEDUP 8 // 8 times more common on bonus levels
- #define NOSE 2 // if (NOSE > PROTECTORS) nose disabled
- #define WORMQUEUELIMIT 15
- #define DOGQUEUELIMIT 120
- #define TIMELIMIT 599
- #define SECONDSPERLEVEL 120 // assert (SECONDSPERLEVEL <= TIMELIMIT);
- #define WEIGHT 5
-
- // dog dormancy
- #define DORMANT 0
- #define AWAKENING 1
- #define CHASING 10
-
- // population limits
- #define CREATURES 50
- #define MAGNETS 20
- #define PROTECTORS 2 // <=4!
- #define OCTOPI 12 // this limit applies only to predefined octopi
-
- #define FREQ_BIRD 140
- #define FREQ_CLOUD 55
- #define FREQ_CLOUDFIRE 30
- #define FREQ_DOG 55
- #define FREQ_DRIP 15
- #define FREQ_FISH 105
- #define FREQ_GIRAFFE 50
- #define FREQ_GOAT 35
- #define FREQ_GOATFIRE 10
- #define FREQ_GOATMOVE 5
- #define FREQ_LION 50
- #define FREQ_LIONTURN 20
- #define FREQ_OCTOPUS 95
- #define FREQ_OCTOPUSFIRE 40
- #define FREQ_OCTOPUSSPIN 3
- #define FREQ_ORB 35
- #define FREQ_PENGUIN 50
- #define FREQ_SLIME 80
- #define FREQ_SLIMEGROW 75
- #define FREQ_TELEPORT 210
- #define FREQ_TIMEBOMB 210
-
- #define SPEED_BIRD 13
- #define SPEED_CLOUD 9
- #define SPEED_DOG 3
- #define SPEED_DRIP 4
- #define SPEED_FISH 12
- #define SPEED_FRAGMENT 3
- #define SPEED_GIRAFFE 255 // giraffe never needs to move
- #define SPEED_GOAT 16
- #define SPEED_LION 9
- #define SPEED_MAGNET 9
- #define SPEED_MISSILE 7
- #define SPEED_OCTOPUS 16
- #define SPEED_ORB 6
- #define SPEED_OTTER 19
- #define SPEED_PENGUIN 11
- #define SPEED_TIMEBOMB 60
- #define SPEED_WHIRLWIND 1
-
- #define HARDNESS_BIRD 50
- #define HARDNESS_CLOUD 50
- #define HARDNESS_DOG 50
- #define HARDNESS_DRIP 50
- #define HARDNESS_FISH 50
- #define HARDNESS_FRAGMENT 50
- #define HARDNESS_GIRAFFE 50
- #define HARDNESS_GOAT 50
- #define HARDNESS_LION 60
- #define HARDNESS_MISSILE 50
- #define HARDNESS_OCTOPUS 50
- #define HARDNESS_OTTER 95
- #define HARDNESS_ORB 50
- #define HARDNESS_PENGUIN 10
- #define HARDNESS_TIMEBOMB 80
- #define HARDNESS_WHIRLWIND 90
-
- #define DISTANCE_FAST 5
- #define DISTANCE_BIRD 3
- #define DISTANCE_GIRAFFE 5
- #define DISTANCE_NORMAL 4
- #define DISTANCE_NOSE 4
- #define DISTANCE_SLOW 3
- #define DISTANCE_VERYSLOW 2
-
- #define POINTS_EMPTY 1
- #define POINTS_DYNAMITE 5
- #define POINTS_TURNSILVER 5
- #define POINTS_ENCLOSURE 10
- #define POINTS_SILVER 10
- #define POINTS_TURNGOLD 10
- #define POINTS_GOLD 20
- #define POINTS_LETTER 100
- #define POINTS_GRAVE 100
-
- #define ADD_BOMB 5 // in squares radius
- #define ADD_CLOCK 10 // in seconds
- #define ADD_CUTTER 10 // in VERYSLOWs
- #define ADD_GLOW 30 // in VERYSLOWs
- #define ADD_ICE 10 // in VERYSLOWs
- #define ADD_ARMOUR 25 // in VERYSLOWs
- #define ADD_TREASURE 10 // in seconds
- #define RAND_BOMB 25
- #define RAND_CLOCK 20
- #define RAND_CUTTER 20
- #define RAND_GLOW 50
- #define RAND_ICE 5
- #define RAND_ARMOUR 25
- #define RAND_TREASURE 10
-
- MODULE void changefield(void);
- MODULE void death(void);
- MODULE void fastloop(void);
- MODULE void killall(void);
- MODULE void magnetloop(void);
- MODULE void newhiscores(void);
- MODULE void slowloop(void);
- MODULE void ReadGameports(void);
- MODULE void endoflevel(void);
-
- MODULE void bangdynamite(SBYTE x, SBYTE y, SBYTE player);
- MODULE void bombblast(SBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey);
- MODULE void bothcol(SBYTE player, SBYTE x, SBYTE y);
- MODULE void bounceoffcreature(UBYTE which, SBYTE x, SBYTE y);
- MODULE void __inline change(SBYTE x, SBYTE y, UBYTE image);
- MODULE void checkrectangle(SBYTE direction, SBYTE player, SBYTE horizontalsize, SBYTE verticalsize);
- MODULE void cloudbullet(UBYTE which, SBYTE x, SBYTE y, SBYTE deltay);
- MODULE void creatureloop(SBYTE which);
- MODULE void dogqueue(SBYTE which, SBYTE deltax, SBYTE deltay);
- MODULE void drawcause(SBYTE player, SBYTE state);
- MODULE void newlevel(UBYTE player);
- MODULE void orbsplit(SBYTE which);
- MODULE void protcol(SBYTE player, SBYTE x, SBYTE y, SBYTE thisprot);
- MODULE void putnumber(void);
- MODULE void ramming(SBYTE player);
- MODULE void reflect(UBYTE which);
- MODULE void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay);
- MODULE void updatearrow(SBYTE arrowy);
- MODULE void wormbullet(SBYTE player);
- MODULE void wormloop(SBYTE player);
- MODULE void wormcol(SBYTE player, SBYTE x, SBYTE y);
-
- MODULE void wormworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2);
- MODULE void protworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2);
- MODULE void protprot(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2);
- MODULE void octopusfire(UBYTE which);
- MODULE void squareblast(SBYTE type, SBYTE player, UBYTE c, SBYTE x, SBYTE y, ABOOL cutter);
- MODULE void drawmissile(SBYTE x, SBYTE y, UBYTE which);
-
- MODULE SWORD atleast(SWORD value, SWORD minimum);
- MODULE ABOOL blocked(UBYTE which, SBYTE deltax, SBYTE deltay);
- MODULE ABOOL bouncecreature(UBYTE which, SBYTE x, SBYTE y);
- MODULE SBYTE bsign(SBYTE value);
- MODULE ABOOL findempty(SBYTE* x, SBYTE* y, ABOOL mode);
- MODULE FLAG getnumber(SBYTE player);
- MODULE SBYTE onlyworm(ABOOL alive);
- MODULE SBYTE slowdown(SBYTE speed, ABOOL brakes);
- MODULE SBYTE speedup(SBYTE speed, ABOOL brakes);
- MODULE UBYTE whichcreature(SBYTE x, SBYTE y, UBYTE species, UBYTE exception);
- MODULE SBYTE whichteleport(SBYTE x, SBYTE y);
- MODULE ULONG wormobject(UBYTE player, SBYTE x, SBYTE y);
-
- MODULE void wormkillcreature(UBYTE player, UBYTE which);
- MODULE void createcreature(UBYTE species, UBYTE which, SBYTE x, SBYTE y, SBYTE deltax, SBYTE deltay, UBYTE player);
- MODULE ULONG arand(ULONG number);
- MODULE void protcreature(UBYTE player, UBYTE which);
- MODULE void wormcreature(UBYTE player, UBYTE which);
- MODULE void creaturecreature(UBYTE which1, UBYTE which2);
-
- /* PRIVATE STRUCTURES -------------------------------------------------- */
-
- struct
- { SBYTE x, y, deltax, deltay;
- ABOOL alive, moved, teleported, visible, reflected;
- } bullet[9];
- struct
- { UWORD freq;
- ULONG score;
- } object[LASTOBJECT + 1] =
- { {1590, 60}, // AFFIXER
- { 65, 20}, // AMMO
- { 105, 20}, // ARMOUR
- { 90, 50}, // BIAS
- { 130, 30}, // BOMB
- { 115, 10}, // BONUS
- { 280, 10}, // BRAKES
- { 890, 60}, // CLOCK
- { 370, 50}, // CONVERTER
- { 300, 80}, // CUTTER
- { 255, 90}, // CYCLONE
- { 315, 20}, // ENCLOSER
- { 115, 30}, // GLOW
- { 205, 50}, // GROWER
- {1900, 90}, // HEALER
- { 950, 60}, // ICE
- { 140, 60}, // LIFE
- { 165, 80}, // LIGHTNING
- { 930, 80}, // MAGNET
- { 210, 40}, // MISSILE
- { 630, 50}, // MULTIPLIER
- { 235, 30}, // POWER
- { 465, 50}, // PROTECTOR
- { 210, 40}, // PULSE
- { 300, 50}, // PUSHER
- { 400, 40}, // REMNANTS
- { 500, 30}, // SIDESHOT
- { 480, 40}, // SLAYER
- { 975, 40}, // SLOWER
- { 710, 70}, // SWITCHER
- {1490, 120}, // TREASURE
- {3885, 140} // UMBRELLA
- };
-
- /* -200 common
- 220-400 uncommon
- 420-980 rare
- 1000+ very rare */
-
- struct
- { SBYTE x, y, deltax, deltay, relx, rely;
- ABOOL alive, last, visible;
- } protector[4][PROTECTORS + 1];
- struct
- { SBYTE deltax, deltay;
- } thewormqueue[4][WORMQUEUELIMIT + 1];
- struct
- { SBYTE deltax, deltay;
- } thedogqueue[CREATURES + 1][DOGQUEUELIMIT + 1];
- struct
- { ABOOL alive;
- SBYTE x, y, player;
- UBYTE object;
- } magnet[MAGNETS + 1];
-
- AGLOBAL UBYTE missileframes[4][MISSILEFRAMES + 1] =
- { { FIRSTMISSILE,
- FIRSTMISSILEFRAME,
- FIRSTMISSILEFRAME + 1,
- FIRSTMISSILEFRAME + 2,
- FIRSTMISSILEFRAME + 3,
- FIRSTMISSILEFRAME + 4
- },
- { FIRSTMISSILE + 1,
- FIRSTMISSILEFRAME + 5,
- FIRSTMISSILEFRAME + 6,
- FIRSTMISSILEFRAME + 7,
- FIRSTMISSILEFRAME + 8,
- FIRSTMISSILEFRAME + 9
- },
- { FIRSTMISSILE + 2,
- FIRSTMISSILEFRAME + 10,
- FIRSTMISSILEFRAME + 11,
- FIRSTMISSILEFRAME + 12,
- FIRSTMISSILEFRAME + 13,
- FIRSTMISSILEFRAME + 14,
- },
- { FIRSTMISSILE + 3,
- FIRSTMISSILEFRAME + 15,
- FIRSTMISSILEFRAME + 16,
- FIRSTMISSILEFRAME + 17,
- FIRSTMISSILEFRAME + 18,
- FIRSTMISSILEFRAME + 19
- } };
-
- UBYTE eachworm[4][2][9] =
- { { { GREENHEAD_NW, GREENHEADUP, GREENHEAD_NE,
- GREENHEADLEFT, ANYTHING, GREENHEADRIGHT,
- GREENHEAD_SW, GREENHEADDOWN, GREENHEAD_SE
- },
- { GREENGLOW_NW, GREENGLOWUP, GREENGLOW_NE,
- GREENGLOWLEFT, ANYTHING, GREENGLOWRIGHT,
- GREENGLOW_SW, GREENGLOWDOWN, GREENGLOW_SE
- } },
- { { REDHEAD_NW, REDHEADUP, REDHEAD_NE,
- REDHEADLEFT, ANYTHING, REDHEADRIGHT,
- REDHEAD_SW, REDHEADDOWN, REDHEAD_SE
- },
- { REDGLOW_NW, REDGLOWUP, REDGLOW_NE,
- REDGLOWLEFT, ANYTHING, REDGLOWRIGHT,
- REDGLOW_SW, REDGLOWDOWN, REDGLOW_SE
- } },
- { { BLUEHEAD_NW, BLUEHEADUP, BLUEHEAD_NE,
- BLUEHEADLEFT, ANYTHING, BLUEHEADRIGHT,
- BLUEHEAD_SW, BLUEHEADDOWN, BLUEHEAD_SE
- },
- { BLUEGLOW_NW, BLUEGLOWUP, BLUEGLOW_NE,
- BLUEGLOWLEFT, ANYTHING, BLUEGLOWRIGHT,
- BLUEGLOW_SW, BLUEGLOWDOWN, BLUEGLOW_SE
- } },
- { { YELLOWHEAD_NW, YELLOWHEADUP, YELLOWHEAD_NE,
- YELLOWHEADLEFT,ANYTHING, YELLOWHEADRIGHT,
- YELLOWHEAD_SW, YELLOWHEADDOWN,YELLOWHEAD_SE
- },
- { YELLOWGLOW_NW, YELLOWGLOWUP, YELLOWGLOW_NE,
- YELLOWGLOWLEFT,ANYTHING, YELLOWGLOWRIGHT,
- YELLOWGLOW_SW, YELLOWGLOWDOWN,YELLOWGLOW_SE
- } } };
-
- UBYTE eachtail[4][2][9][9] = {
- { { { GN_SE_NW, GN_SE_N, GN_SE_NE, // going NW (delta -1, -1)
- GN_SE_W, WHATEVER, GN_SE_E, // (so starting from SE)
- GN_SE_SW, GN_SE_S, GN_SE_NW
- },
- { GN_S_NW, GN_S_N, GN_S_NE, // going N (delta 0, -1)
- GN_S_W, WHATEVER, GN_S_E, // (so starting from S)
- GN_S_SW, GN_S_N, GN_S_SE
- },
- { GN_SW_NW, GN_SW_N, GN_SW_NE, // going NE (delta 0, 1)
- GN_SW_W, WHATEVER, GN_SW_E, // (so starting from SW)
- GN_SW_NE, GN_SW_S, GN_SW_SE
- },
- { GN_E_NW, GN_E_N, GN_E_NE, // going W (delta -1, 0)
- GN_E_W, WHATEVER, GN_E_W, // (so starting from E)
- GN_E_SW, GN_E_S, GN_E_SE
- },
- { GN_SE_NW, GN_S_N, GN_SW_NE, // going nowhere (delta 0, 0)
- GN_E_W, WHATEVER, GN_W_E,
- GN_NE_SW, GN_N_S, GN_NW_SE
- },
- { GN_W_NW, GN_W_N, GN_W_NE, // going E (delta 1, 0)
- GN_W_E, WHATEVER, GN_W_E, // (so starting from W)
- GN_W_SW, GN_W_S, GN_W_SE
- },
- { GN_NE_NW, GN_NE_N, GN_NE_NW, // going SW (delta -1, 1)
- GN_NE_W, WHATEVER, GN_NE_E, // (so starting from NE)
- GN_NE_SW, GN_NE_S, GN_NE_SE
- },
- { GN_N_NW, GN_N_S, GN_N_NE, // going S (delta 0, 1)
- GN_N_W, WHATEVER, GN_N_E, // (so starting from N)
- GN_N_SW, GN_N_S, GN_N_SE
- },
- { GN_NW_SE, GN_NW_N, GN_NW_NE, // going SE (delta 1, 1)
- GN_NW_W, WHATEVER, GN_NW_E, // (so starting from NW)
- GN_NW_SW, GN_NW_S, GN_NW_SE
- } },
- { { GG_SE_NW, GG_SE_N, GG_SE_NE, // going NW (delta -1, -1)
- GG_SE_W, WHATEVER, GG_SE_E, // (so starting from SE)
- GG_SE_SW, GG_SE_S, GG_SE_NW
- },
- { GG_S_NW, GG_S_N, GG_S_NE, // going N (delta 0, -1)
- GG_S_W, WHATEVER, GG_S_E, // (so starting from S)
- GG_S_SW, GG_S_N, GG_S_SE
- },
- { GG_SW_NW, GG_SW_N, GG_SW_NE, // going NE (delta 0, 1)
- GG_SW_W, WHATEVER, GG_SW_E, // (so starting from SW)
- GG_SW_NE, GG_SW_S, GG_SW_SE
- },
- { GG_E_NW, GG_E_N, GG_E_NE, // going W (delta -1, 0)
- GG_E_W, WHATEVER, GG_E_W, // (so starting from E)
- GG_E_SW, GG_E_S, GG_E_SE
- },
- { GG_SE_NW, GG_S_N, GG_SW_NE, // going nowhere (delta 0, 0)
- GG_E_W, WHATEVER, GG_W_E,
- GG_NE_SW, GG_N_S, GG_NW_SE
- },
- { GG_W_NW, GG_W_N, GG_W_NE, // going E (delta 1, 0)
- GG_W_E, WHATEVER, GG_W_E, // (so starting from W)
- GG_W_SW, GG_W_S, GG_W_SE
- },
- { GG_NE_NW, GG_NE_N, GG_NE_SW, // going SW (delta -1, 1)
- GG_NE_W, WHATEVER, GG_NE_E, // (so starting from NE)
- GG_NE_SW, GG_NE_S, GG_NE_SE
- },
- { GG_N_NW, GG_N_S, GG_N_NE, // going S (delta 0, 1)
- GG_N_W, WHATEVER, GG_N_E, // (so starting from N)
- GG_N_SW, GG_N_S, GG_N_SE
- },
- { GG_NW_SE, GG_NW_N, GG_NW_NE, // going SE (delta 1, 1)
- GG_NW_W, WHATEVER, GG_NW_E, // (so starting from NW)
- GG_NW_SW, GG_NW_S, GG_NW_SE
- } } },
- { { { RN_SE_NW, RN_SE_N, RN_SE_NE, // going NW (delta -1, -1)
- RN_SE_W, WHATEVER, RN_SE_E, // (so starting from SE)
- RN_SE_SW, RN_SE_S, RN_SE_NW,
- },
- { RN_S_NW, RN_S_N, RN_S_NE, // going N (delta 0, -1)
- RN_S_W, WHATEVER, RN_S_E, // (so starting from S)
- RN_S_SW, RN_S_N, RN_S_SE
- },
- { RN_SW_NW, RN_SW_N, RN_SW_NE, // going NE (delta 0, 1)
- RN_SW_W, WHATEVER, RN_SW_E, // (so starting from SW)
- RN_SW_NE, RN_SW_S, RN_SW_SE
- },
- { RN_E_NW, RN_E_N, RN_E_NE, // going W (delta -1, 0)
- RN_E_W, WHATEVER, RN_E_W, // (so starting from E)
- RN_E_SW, RN_E_S, RN_E_SE
- },
- { RN_SE_NW, RN_S_N, RN_SW_NE, // going nowhere (delta 0, 0)
- RN_E_W, WHATEVER, RN_W_E,
- RN_NE_SW, RN_N_S, RN_NW_SE
- },
- { RN_W_NW, RN_W_N, RN_W_NE, // going E (delta 1, 0)
- RN_W_E, WHATEVER, RN_W_E, // (so starting from W)
- RN_W_SW, RN_W_S, RN_W_SE
- },
- { RN_NE_NW, RN_NE_N, RN_NE_SW, // going SW (delta -1, 1)
- RN_NE_W, WHATEVER, RN_NE_E, // (so starting from NE)
- RN_NE_SW, RN_NE_S, RN_NE_SE
- },
- { RN_N_NW, RN_N_S, RN_N_NE, // going S (delta 0, 1)
- RN_N_W, WHATEVER, RN_N_E, // (so starting from N)
- RN_N_SW, RN_N_S, RN_N_SE
- },
- { RN_NW_SE, RN_NW_N, RN_NW_NE, // going SE (delta 1, 1)
- RN_NW_W, WHATEVER, RN_NW_E, // (so starting from NW)
- RN_NW_SW, RN_NW_S, RN_NW_SE
- } },
- { { RG_SE_NW, RG_SE_N, RG_SE_NE, // going NW (delta -1, -1)
- RG_SE_W, WHATEVER, RG_SE_E, // (so starting from SE)
- RG_SE_SW, RG_SE_S, RG_SE_NW
- },
- { RG_S_NW, RG_S_N, RG_S_NE, // going N (delta 0, -1)
- RG_S_W, WHATEVER, RG_S_E, // (so starting from S)
- RG_S_SW, RG_S_N, RG_S_SE
- },
- { RG_SW_NW, RG_SW_N, RG_SW_NE, // going NE (delta 0, 1)
- RG_SW_W, WHATEVER, RG_SW_E, // (so starting from SW)
- RG_SW_NE, RG_SW_S, RG_SW_SE
- },
- { RG_E_NW, RG_E_N, RG_E_NE, // going W (delta -1, 0)
- RG_E_W, WHATEVER, RG_E_W, // (so starting from E)
- RG_E_SW, RG_E_S, RG_E_SE
- },
- { RG_SE_NW, RG_S_N, RG_SW_NE, // going nowhere (delta 0, 0)
- RG_E_W, WHATEVER, RG_W_E,
- RG_NE_SW, RG_N_S, RG_NW_SE
- },
- { RG_W_NW, RG_W_N, RG_W_NE, // going E (delta 1, 0)
- RG_W_E, WHATEVER, RG_W_E, // (so starting from W)
- RG_W_SW, RG_W_S, RG_W_SE
- },
- { RG_NE_NW, RG_NE_N, RG_NE_SW, // going SW (delta -1, 1)
- RG_NE_W, WHATEVER, RG_NE_E, // (so starting from NE)
- RG_NE_SW, RG_NE_S, RG_NE_SE
- },
- { RG_N_NW, RG_N_S, RG_N_NE, // going S (delta 0, 1)
- RG_N_W, WHATEVER, RG_N_E, // (so starting from N)
- RG_N_SW, RG_N_S, RG_N_SE
- },
- { RG_NW_SE, RG_NW_N, RG_NW_NE, // going SE (delta 1, 1)
- RG_NW_W, WHATEVER, RG_NW_E, // (so starting from NW)
- RG_NW_SW, RG_NW_S, RG_NW_SE
- } } },
- { { { BN_NW_SE, BN_N_SE, BN_NE_SE, // going NW (delta -1, -1)
- BN_W_SE, WHATEVER, BN_E_SE, // (so starting from SE)
- BN_SW_SE, BN_S_SE, BN_NW_SE
- },
- { BN_NW_S, BN_N_S, BN_NE_S, // going N (delta 0, -1)
- BN_W_S, WHATEVER, BN_E_S, // (so starting from S)
- BN_S_SW, BN_N_S, BN_S_SE
- },
- { BN_NW_SW, BN_N_SW, BN_NE_SW, // going NE (delta 0, 1)
- BN_W_SW, WHATEVER, BN_SW_E, // (so starting from SW)
- BN_NE_SW, BN_S_SW, BN_SW_SE
- },
- { BN_NW_E, BN_N_E, BN_E_NE, // going W (delta -1, 0)
- BN_W_E, WHATEVER, BN_W_E, // (so starting from E)
- BN_SW_E, BN_E_S, BN_E_SE
- },
- { BN_NW_SE, BN_N_S, BN_NE_SW, // going nowhere (delta 0, 0)
- BN_W_E, WHATEVER, BN_W_E,
- BN_NE_SW, BN_N_S, BN_NW_SE
- },
- { BN_W_NW, BN_N_W, BN_W_NE, // going E (delta 1, 0)
- BN_W_E, WHATEVER, BN_W_E, // (so starting from W)
- BN_W_SW, BN_W_S, BN_W_SE
- },
- { BN_NW_NE, BN_N_NE, BN_NE_SW, // going SW (delta -1, 1)
- BN_W_NE, WHATEVER, BN_E_NE, // (so starting from NE)
- BN_NE_SW, BN_NE_S, BN_NE_SE
- },
- { BN_N_NW, BN_N_S, BN_N_NE, // going S (delta 0, 1)
- BN_N_W, WHATEVER, BN_N_E, // (so starting from N)
- BN_N_SW, BN_N_S, BN_N_SE
- },
- { BN_SW_SE, BN_N_NW, BN_NW_NE, // going SE (delta 1, 1)
- BN_W_NW, WHATEVER, BN_NW_E, // (so starting from NW)
- BN_NW_SW, BN_NW_S, BN_NW_SE
- } },
- { { BG_NW_SE, BG_N_SE, BG_NE_SE, // going NW (delta -1, -1)
- BG_W_SE, WHATEVER, BG_E_SE, // (so starting from SE)
- BG_SW_SE, BG_S_SE, BG_NW_SE
- },
- { BG_NW_S, BG_N_S, BG_NE_S, // going N (delta 0, -1)
- BG_W_S, WHATEVER, BG_E_S, // (so starting from S)
- BG_S_SW, BG_N_S, BG_S_SE
- },
- { BG_NW_SW, BG_N_SW, BG_NE_SW, // going NE (delta 0, 1)
- BG_W_SW, WHATEVER, BG_SW_E, // (so starting from SW)
- BG_NE_SW, BG_S_SW, BG_SW_SE
- },
- { BG_NE_E, BG_N_E, BG_NE_E, // going W (delta -1, 0)
- BG_W_E, WHATEVER, BG_W_E, // (so starting from E)
- BG_SW_E, BG_E_S, BG_E_SE
- },
- { BG_NW_SE, BG_N_S, BG_NE_SW, // going nowhere (delta 0, 0)
- BG_W_E, WHATEVER, BG_W_E,
- BG_NE_SW, BG_N_S, BG_NW_SE
- },
- { BG_NW_W, BG_N_W, BG_NE_W, // going E (delta 1, 0)
- BG_W_E, WHATEVER, BG_W_E, // (so starting from W)
- BG_W_SW, BG_W_S, BG_W_SE
- },
- { BG_NW_NE, BG_N_NE, BG_NE_SW, // going SW (delta -1, 1)
- BG_NE_W, WHATEVER, BG_NE_E, // (so starting from NE)
- BG_NE_SW, BG_NE_S, BG_NE_SE
- },
- { BG_N_NW, BG_N_S, BG_N_NE, // going S (delta 0, 1)
- BG_N_W, WHATEVER, BG_N_E, // (so starting from N)
- BG_N_SW, BG_N_S, BG_N_SE
- },
- { BG_NW_SE, BG_N_NW, BG_NW_NE, // going SE (delta 1, 1)
- BG_NW_W, WHATEVER, BG_NW_E, // (so starting from NW)
- BG_NW_SW, BG_NW_S, BG_NW_SE
- } } },
- { { { YN_NW_SE, YN_N_SE, YN_NE_SE, // going NW (delta -1, -1)
- YN_W_SE, WHATEVER, YN_E_SE, // (so starting from SE)
- YN_SW_SE, YN_S_SE, YN_NW_SE
- },
- { YN_NW_S, YN_N_S, YN_NE_S, // going N (delta 0, -1)
- YN_W_S, WHATEVER, YN_S_E, // (so starting from S)
- YN_S_SW, YN_N_S, YN_S_SE
- },
- { YN_NW_SW, YN_N_SW, YN_NE_SW, // going NE (delta 0, 1)
- YN_W_SW, WHATEVER, YN_E_SW, // (so starting from SW)
- YN_NE_SW, YN_S_SW, YN_SW_SE
- },
- { YN_NW_E, YN_N_E, YN_NE_E, // going W (delta -1, 0)
- YN_W_E, WHATEVER, YN_W_E, // (so starting from E)
- YN_E_SW, YN_S_E, YN_E_SE
- },
- { YN_NW_SE, YN_N_S, YN_NE_SW, // going nowhere (delta 0, 0)
- YN_W_E, WHATEVER, YN_W_E,
- YN_NE_SW, YN_N_S, YN_NW_SE
- },
- { YN_NW_W, YN_N_W, YN_W_NE, // going E (delta 1, 0)
- YN_W_E, WHATEVER, YN_W_E, // (so starting from W)
- YN_W_SW, YN_W_S, YN_W_SE
- },
- { YN_NW_NE, YN_N_NE, YN_NE_SW, // going SW (delta -1, 1)
- YN_W_NE, WHATEVER, YN_NE_E, // (so starting from NE)
- YN_NE_SW, YN_NE_S, YN_NE_SE
- },
- { YN_N_NW, YN_N_S, YN_N_NE, // going S (delta 0, 1)
- YN_N_W, WHATEVER, YN_N_E, // (so starting from N)
- YN_N_SW, YN_N_S, YN_N_SE
- },
- { YN_NW_SE, YN_N_NW, YN_NW_NE, // going SE (delta 1, 1)
- YN_NW_W, WHATEVER, YN_NW_E, // (so starting from NW)
- YN_NW_SW, YN_NW_S, YN_NW_SE
- } },
- { { YG_NW_SE, YG_N_SE, YG_NE_SE, // going NW (delta -1, -1)
- YG_W_SE, WHATEVER, YG_E_SE, // (so starting from SE)
- YG_SW_SE, YG_S_SE, YG_NW_SE
- },
- { YG_S_NW, YG_N_S, YG_S_NE, // going N (delta 0, -1)
- YG_W_S, WHATEVER, YG_E_S, // (so starting from S)
- YG_S_SW, YG_N_S, YG_S_SE
- },
- { YG_NW_SW, YG_N_SW, YG_NE_SW, // going NE (delta 0, 1)
- YG_W_SW, WHATEVER, YG_E_SW, // (so starting from SW)
- YG_NE_SW, YG_S_SW, YG_SW_SE
- },
- { YG_E_NW, YG_E_N, YG_E_NE, // going W (delta -1, 0)
- YG_W_E, WHATEVER, YG_W_E, // (so starting from E)
- YG_E_SW, YG_E_S, YG_E_SE
- },
- { YG_NW_SE, YG_N_S, YG_NE_SW, // going nowhere (delta 0, 0)
- YG_W_E, WHATEVER, YG_W_E,
- YG_NE_SW, YG_N_S, YG_NW_SE
- },
- { YG_W_NW, YG_N_W, YG_W_NE, // going E (delta 1, 0)
- YG_W_E, WHATEVER, YG_W_E, // (so starting from W)
- YG_W_SW, YG_W_S, YG_W_SE
- },
- { YG_NW_NE, YG_N_NE, YG_NE_SW, // going SW (delta -1, 1)
- YG_W_NE, WHATEVER, YG_E_NE, // (so starting from NE)
- YG_NE_SW, YG_S_NE, YG_NE_SE
- },
- { YG_N_NW, YG_N_S, YG_N_NE, // going S (delta 0, 1)
- YG_N_W, WHATEVER, YG_E_N, // (so starting from N)
- YG_N_SW, YG_N_S, YG_N_SE
- },
- { YG_NW_SE, YG_N_NW, YG_NW_NE, // going SE (delta 1, 1)
- YG_W_NW, WHATEVER, YG_E_NW, // (so starting from NW)
- YG_NW_SW, YG_S_NW, YG_NW_SE
- } } }
- };
-
- /* Rules for variable types:
-
- SBYTE is used for field coordinates and queue indexes
- UBYTE is used for field contents
- SWORD is used for frequencies
- ULONG is used for scores */
-
- struct
- { ABOOL alive, visible;
- SBYTE x, y, deltax, deltay, pos, time, dir;
- UBYTE dormant, multi, speed, last, oldlast, species, hardness, frame,
- journey, going, then,
- type; // type is worm 0-3 (for drips, missiles, dogs and birds)
- SWORD freq;
- ULONG score;
- } creature[CREATURES + 1];
-
- // MODULE VARIABLES (used only within engine.c) ---------------------------
-
- MODULE ABOOL banging = FALSE,
- first = TRUE,
- enclosed = FALSE,
- trainer;
- MODULE UBYTE infector[FIELDX + 1][FIELDY + 1],
- ice,
- leveltype;
- MODULE SBYTE numberx,
- numbery,
- number,
- treasurer;
-
- // GLOBAL VARIABLES -------------------------------------------------------
-
- ABOOL anims = TRUE,
- clearthem = FALSE,
- modified = FALSE,
- randomflag = FALSE,
- randomarray[MAXLEVELS + 1],
- thick = FALSE,
- turbo = FALSE;
- UBYTE board[MAXLEVELS + 1][FIELDX + 1][FIELDY + 1],
- field[FIELDX + 1][FIELDY + 1];
- SBYTE a = GAMEOVER,
- players,
- level = 1, levels, reallevel, sourcelevel,
- startx[MAXLEVELS + 1], starty[MAXLEVELS + 1];
- SWORD secondsleft, secondsperlevel;
- TEXT pathname[81],
- date[DATELENGTH + 1],
- times[TIMELENGTH + 1];
- ULONG delay, r;
-
- AGLOBAL struct HiScoreStruct hiscore[HISCORES + 1];
- AGLOBAL struct WormStruct worm[4];
- AGLOBAL struct TeleportStruct teleport[MAXLEVELS + 1][4];
-
- MODULE ABOOL blocked(UBYTE which, SBYTE deltax, SBYTE deltay)
- { UBYTE c = field[xwrap(teleport[level][partner(which)].x + deltax)][ywrap(teleport[level][partner(which)].y + deltay)];
- if (c == STONE || c == METAL || c == GOAT || c == OCTOPUS)
- return TRUE;
- else return FALSE;
- }
-
- MODULE void bombblast(SBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey)
- { SBYTE counter, downy, downymax, leftx, leftxmax, rightx, rightxmax, strength, uppy, uppymax, x, y;
-
- effect(FXUSE_BOMB);
- strength = ADD_BOMB + arand(RAND_BOMB);
-
- leftxmax = centrex - strength;
- if (leftxmax < 0)
- leftxmax = 0;
- rightxmax = centrex + strength;
- if (rightxmax > FIELDX)
- rightxmax = FIELDX;
- uppymax = centrey - strength;
- if (uppymax < 0)
- uppymax = 0;
- downymax = centrey + strength;
- if (downymax > FIELDY)
- downymax = FIELDY;
-
- leftx = centrex;
- rightx = centrex;
- uppy = centrey;
- downy = centrey;
- for (counter = 1; counter <= strength; counter++)
- { if (leftx > leftxmax)
- { leftx--;
- for (y = uppy; y <= downy; y++)
- squareblast(triggerer, player, field[leftx][y], leftx, y, FALSE);
- }
- if (uppy > uppymax)
- { uppy--;
- for (x = leftx; x <= rightx; x++)
- squareblast(triggerer, player, field[x][uppy], x, uppy, FALSE);
- }
- if (rightx < rightxmax)
- { rightx++;
- for (y = downy; y >= uppy; y--)
- squareblast(triggerer, player, field[rightx][y], rightx, y, FALSE);
- }
- if (downy < downymax)
- { downy++;
- for (x = rightx; x >= leftx; x--)
- squareblast(triggerer, player, field[x][downy], x, downy, FALSE);
- } } }
-
- MODULE void bounceoffcreature(UBYTE which, SBYTE x, SBYTE y)
- { UBYTE killed;
-
- if (field[x][y] == GOAT || field[x][y] == OCTOPUS || field[x][y] == FISH)
- { killed = whichcreature(x, y, field[x][y], which);
- creature[killed].alive = FALSE;
- change(x, y, BONUS);
- } }
-
- MODULE ABOOL bouncecreature(UBYTE which, SBYTE x, SBYTE y)
- { if
- ( field[x][y] == METAL
- || field[x][y] == STONE
- || field[x][y] == WOOD
- || field[x][y] == GOAT
- || field[x][y] == OCTOPUS
- || field[x][y] == FISH
- || (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
- )
- { return TRUE;
- } else
- { return FALSE;
- } }
-
- MODULE SBYTE bsign(SBYTE value)
- { if (value < 0)
- return (-1);
- elif (value > 0)
- return (1);
- else return (0);
- }
-
- MODULE void changefield(void)
- { SBYTE x, y;
-
- if (randomflag && a == PLAYGAME && level)
- { do
- { sourcelevel = arand(levels - 1) + 1;
- } while (randomarray[level]);
- randomarray[level] = TRUE;
- } else sourcelevel = level;
-
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- field[x][y] = board[sourcelevel][x][y];
- }
-
- void clearhiscores(void)
- { SBYTE i;
-
- clearthem = FALSE;
- for (i = 0; i <= HISCORES; i++)
- { hiscore[i].player = -1;
- hiscore[i].level = 0;
- hiscore[i].score = 0;
- hiscore[i].fresh = FALSE;
- hiscore[i].name[0] = 0;
- hiscore[i].time[0] = 0;
- hiscore[i].date[0] = 0;
- } }
-
- MODULE void death(void)
- { SBYTE pain, player;
- UBYTE which;
- ABOOL slow;
-
- for (player = 0; player <= 3; player++)
- { if (worm[player].lives)
- { if (!worm[player].alive)
- { slow = FALSE;
- pain = 0;
- if (worm[player].cause >= FIRSTTAIL && worm[player].cause <= LASTTAIL)
- { if (player == worm[player].cause - FIRSTTAIL)
- pain = PAIN_FRIENDLYTAIL;
- else pain = PAIN_ENEMYTAIL;
- slow = TRUE;
- } elif (worm[player].cause >= FIRSTGLOW && worm[player].cause <= LASTGLOW)
- { pain = PAIN_GLOW;
- slow = TRUE;
- } elif (worm[player].cause >= FIRSTFIRE && worm[player].cause <= LASTFIRE)
- pain = PAIN_WORMFIRE;
- elif (worm[player].cause >= FIRSTHEAD && worm[player].cause <= LASTHEAD)
- pain = PAIN_HEAD;
- elif (worm[player].cause >= FIRSTPROTECTOR && worm[player].cause <= LASTPROTECTOR)
- pain = PAIN_PROTECTOR;
- elif (worm[player].cause >= FIRSTMISSILE && worm[player].cause <= LASTMISSILE)
- pain = PAIN_MISSILE;
- elif (worm[player].cause >= FIRSTDRIP && worm[player].cause <= LASTDRIP)
- pain = PAIN_DRIP;
- else switch (worm[player].cause)
- {
- case GOAT:
- pain = PAIN_GOAT;
- slow = TRUE;
- break;
- case OCTOPUS:
- pain = PAIN_OCTOPUS;
- slow = TRUE;
- break;
- case METAL:
- pain = PAIN_METAL;
- slow = TRUE;
- break;
- case SLIME:
- pain = PAIN_SLIME;
- slow = TRUE;
- break;
- case STONE:
- pain = PAIN_STONE;
- slow = TRUE;
- break;
- case TELEPORT:
- pain = PAIN_TELEPORT;
- slow = TRUE;
- break;
- case WOOD:
- pain = PAIN_WOOD;
- slow = TRUE;
- break;
- case BIRD:
- pain = PAIN_BIRD;
- break;
- case BOMB:
- pain = PAIN_BOMB;
- break;
- case CLOUD:
- pain = PAIN_CLOUD;
- break;
- case DOG:
- pain = PAIN_DOG;
- break;
- case FRAGMENT:
- pain = PAIN_FRAGMENT;
- break;
- case LIGHTNING:
- pain = PAIN_LIGHTNING;
- break;
- case ORB:
- pain = PAIN_ORB;
- break;
- case OTTER:
- pain = PAIN_OTTER;
- break;
- case PENGUIN:
- pain = PAIN_PENGUIN;
- break;
- case SLAYER:
- pain = PAIN_SLAYER;
- break;
- case WHIRLWIND:
- pain = PAIN_WHIRLWIND;
- break;
- default:
- // assert(0);
- break;
- }
- if (worm[player].victor >= 0 && worm[player].victor != player)
- { if (worm[worm[player].victor].bias)
- { worm[worm[player].victor].lives += pain;
- stat(worm[player].victor, LIFE);
- } }
- if (slow)
- { worm[player].speed = slowdown(worm[player].speed, worm[player].brakes);
- stat(player, BRAKES);
- }
- if (pain > worm[player].lives)
- worm[player].lives = 0;
- else worm[player].lives -= pain;
-
- draw(worm[player].x, worm[player].y, FIRSTPAIN + player);
- drawcause(player, NORMAL);
- stat(player, LIFE);
- if (level)
- worm[player].levelreached = level;
- else worm[player].levelreached = reallevel;
- if (worm[player].lives)
- { effect(FXPAIN + player);
- worm[player].alive = TRUE;
- worm[player].causewait = r + CAUSEWAIT;
- } else
- { /* kill worm */
- effect(FXDEATH_WORM);
- change(worm[player].x, worm[player].y, FIRSTGRAVE + player);
- updatearrow(worm[player].y);
- for (which = 0; which <= PROTECTORS; which++)
- if (protector[player][which].alive && protector[player][which].visible)
- change(protector[player][which].x, protector[player][which].y, EMPTY);
- for (which = 0; which <= MAGNETS; which++)
- if (magnet[which].player == player)
- magnet[which].alive = FALSE;
- if (worm[player].score >= worm[player].hiscore)
- worm[player].hiscore = worm[player].score;
- } } } }
-
- if (!worm[0].lives && !worm[1].lives && !worm[2].lives && !worm[3].lives)
- { /* End of game */
- for (player = 0; player <= 3; player++)
- if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
- worm[player].hiscore = worm[player].score;
- newhiscores();
- effect(FXGAMEOVER);
- a = GAMEOVER;
- if (players == 1)
- say((STRPTR) "Game over!", worm[onlyworm(FALSE)].colour);
- elif (worm[0].control && ((!worm[1].control) || worm[1].score < worm[0].score) && ((!worm[2].control) || worm[2].score < worm[0].score) && ((!worm[3].control) || worm[3].score < worm[0].score))
- say((STRPTR) "Green wins!", GREEN);
- elif (worm[1].control && ((!worm[0].control) || worm[0].score < worm[1].score) && ((!worm[2].control) || worm[2].score < worm[1].score) && ((!worm[3].control) || worm[3].score < worm[1].score))
- say((STRPTR) "Red wins!", RED);
- elif (worm[2].control && ((!worm[0].control) || worm[0].score < worm[2].score) && ((!worm[1].control) || worm[1].score < worm[2].score) && ((!worm[3].control) || worm[3].score < worm[2].score))
- say((STRPTR) "Blue wins!", BLUE);
- elif (worm[3].control && ((!worm[0].control) || worm[0].score < worm[3].score) && ((!worm[1].control) || worm[1].score < worm[3].score) && ((!worm[2].control) || worm[2].score < worm[3].score))
- say((STRPTR) "Yellow wins!", YELLOW);
- else say((STRPTR) "A draw!", WHITE);
- waitasec();
- anykey(FALSE);
- } }
-
- MODULE void drawcause(SBYTE player, SBYTE state)
- { if (state == BLACK)
- { draw
- ( -6,
- (player * 10) + 8,
- BLACKENED
- );
- } else
- { draw
- ( -6,
- (player * 10) + 8,
- worm[player].cause
- );
- } }
-
- /* NAME enginesetup -- once-only initialization of engine variables
- SYNOPSIS enginesetup(void);
- FUNCTION Sets up the unchanging worm variables.
- MODULE engine.c */
-
- void enginesetup(void)
- { worm[0].statx = worm[0].staty = worm[1].staty = worm[2].statx = 0;
- worm[1].statx = worm[2].staty = worm[3].statx = worm[3].staty = 1;
- worm[0].colour = GREEN;
- worm[1].colour = RED;
- worm[2].colour = BLUE;
- worm[3].colour = YELLOW;
- worm[0].dimcolour = DARKGREEN;
- worm[1].dimcolour = DARKRED;
- worm[2].dimcolour = DARKBLUE;
- worm[3].dimcolour = DARKYELLOW;
- worm[0].port = 2;
- worm[1].port = 3;
- worm[2].port = 1;
- worm[3].port = 0;
- worm[0].name[0] = worm[1].name[0] = worm[2].name[0] = worm[3].name[0] = 0;
- worm[0].dynamitescore =
- worm[1].dynamitescore =
- worm[2].dynamitescore =
- worm[3].dynamitescore = 0;
-
- strcpy(pathname, DEFAULTSET);
-
- systemsetup();
- }
-
- /* NAME fastloop -- things done often
- SYNOPSIS fastloop(void);
- FUNCTION Checks for and handles level completion.
- MODULE engine.c */
-
- MODULE void fastloop(void)
- { SBYTE i, player, x, y;
-
- // all octopi spin together, but some may not be spinning, each may
- // be in a different part of its spin.
- if (!arand(FREQ_OCTOPUSSPIN))
- { for (i = 0; i <= CREATURES; i++)
- { if (creature[i].alive && creature[i].species == OCTOPUS && creature[i].dir >= 0)
- { octopusfire(i);
- } } }
-
- // animate
- if (anims)
- { for (i = 0; i <= CREATURES; i++)
- { if (creature[i].alive && creature[i].visible)
- { if (creature[i].species == BIRD)
- { if (!(r % 3))
- { creature[i].frame += creature[i].dir;
- draw(creature[i].x, creature[i].y, BIRD + creature[i].frame);
- if (creature[i].frame == 0)
- { creature[i].dir = 1;
- } elif (creature[i].frame == 4)
- { creature[i].dir = -1;
- } } }
- elif (creature[i].species == MISSILE)
- { if (!(r % 3))
- { drawmissile(creature[i].x, creature[i].y, i);
- if (++creature[i].frame > MISSILEFRAMES)
- { creature[i].frame = 0;
- } } } } } }
-
- if (banging)
- { banging = FALSE;
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == BANGDYNAMITE)
- { change(x, y, SILVER);
- bangdynamite(x, y, infector[x][y]);
- }
- for (i = 0; i <= 3; i++)
- if (worm[i].dynamitescore)
- { wormscore(i, worm[i].dynamitescore);
- worm[i].dynamitescore = 0;
- }
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == TEMPBANGDYNAMITE)
- { banging = TRUE;
- field[x][y] = BANGDYNAMITE;
- } }
-
- /* DYNAMITE PHILOSOPHY:
-
- Worm gets dynamite. Instantly the dynamite infects the surrounding
- dynamite into bang-dynamite.
- Each fastloop, you scan the field for bang-dynamite. For each
- piece you find, it turns to silver and infects any surrounding dynamite.
-
- flash letter */
-
- if (level)
- { if (r % 8 == 1)
- { draw(numberx, numbery, WHITENED);
- } elif (r % 8 == 2)
- { draw(numberx, numbery, FIRSTLETTER + number - 1);
- } }
-
- // flash icons
- for (player = 0; player <= 3; player++)
- { icon(player, GLOW);
- icon(player, CUTTER);
- } }
-
- MODULE ABOOL findempty(SBYTE* x, SBYTE* y, ABOOL mode)
- { SBYTE count = 0, xx, yy;
- UBYTE c;
-
- if (mode)
- { do
- { xx = arand(FIELDX);
- yy = arand(FIELDY);
- c = field[xx][yy];
- } while ((c != SLIME && c != WOOD && c != STONE && c != METAL && (c < FIRSTTAIL || c > LASTTAIL)) && ++count < PATIENCE);
- } else
- { do
- { xx = arand(FIELDX);
- yy = arand(FIELDY);
- c = field[xx][yy];
- } while ((c < FIRSTEMPTY || c > LASTEMPTY) && ++count < PATIENCE);
- }
-
- if (count < PATIENCE)
- { *x = xx;
- *y = yy;
- return(TRUE);
- } else
- { return(FALSE);
- } }
-
- void gameloop(void)
- { SBYTE i, player;
-
- if (a == PLAYGAME)
- { ReadGameports();
- fastloop();
- gameinput();
- }
- if (a == PLAYGAME)
- { ReadGameports();
- for (player = 0; player <= 3; player++)
- if (worm[player].lives && !(r % worm[player].speed))
- wormloop(player);
- }
- if (a == PLAYGAME)
- { ReadGameports();
- for (i = 0; i <= CREATURES; i++)
- { if (creature[i].alive && !(r % creature[i].speed) && (!ice || creature[i].species == MISSILE || creature[i].species == FRAGMENT))
- { creatureloop(i);
- } } }
- if (a == PLAYGAME)
- { ReadGameports();
- if (!(r % SPEED_MAGNET))
- { magnetloop();
- }
- death();
- }
- if (a == PLAYGAME)
- { ReadGameports();
- if (!(r % VERYSLOW))
- { slowloop();
- } }
- timing();
- }
-
- MODULE void killall(void)
- { UBYTE i;
-
- for (i = 0; i <= CREATURES; i++)
- creature[i].alive = FALSE;
- for (i = 0; i <= MAGNETS; i++)
- magnet[i].alive = FALSE;
- teleport[level][2].alive = FALSE;
- teleport[level][3].alive = FALSE;
- }
-
- SBYTE loadfields(STRPTR fieldname)
- { SBYTE i, j, x, y;
- TEXT IOBuffer[NAMELENGTH + 1];
- UBYTE ver;
-
- #ifdef PLATFORM_IBM
- UBYTE amigaboard[AMIGAFIELDX + 1][FIELDY + 1];
- #endif
-
- /* This routine is not entirely robust, especially regarding
- failures part way through reading. It is very trusting of its data;
- ie. it doesn't do any sanity checking.
-
- Provided that the fieldset was created with Worm Wars's built-in field
- editor, and the file is not corrupt, these failures should never
- happen anyway.
-
- open file */
-
- // say("Opening...", WHITE);
-
- if (!ZOpen(fieldname, FALSE))
- return 1; /* no harm done */
-
- /* read header
-
- say("Reading header...", WHITE);
-
- FSET 7.0#!
- 0123456789
-
- # is the NULL terminator
- ! is levels */
-
- if (!ZRead(IOBuffer, 10))
- { ZClose();
- return 2; /* no harm done */
- }
- if (!strcmp(IOBuffer, "FSET 7.0"))
- { ver = 70;
- } elif (!strcmp(IOBuffer, "FSET 7.2"))
- { ver = 72;
- } else
- { ZClose();
- return 3; /* no harm done */
- }
- levels = IOBuffer[9];
-
- /* read high score table */
-
- // say("Reading high score table...", WHITE);
-
- for (i = 0; i <= HISCORES; i++)
- { if (!ZRead(IOBuffer, 6))
- { ZClose();
- return 4; /* incorrect levels */
- }
- hiscore[i].fresh = FALSE;
- hiscore[i].player = IOBuffer[0];
- hiscore[i].level = IOBuffer[1];
- hiscore[i].score = (IOBuffer[2] * 16777216)
- + (IOBuffer[3] * 65536)
- + (IOBuffer[4] * 256)
- + IOBuffer[5];
-
- if (!ZRead(IOBuffer, NAMELENGTH + 1))
- { ZClose();
- return 5; /* incorrect levels, corrupted high scores */
- }
- for (j = 0; j <= NAMELENGTH; j++)
- { hiscore[i].name[j] = IOBuffer[j];
- }
- if (!ZRead(IOBuffer, TIMELENGTH + 1))
- { ZClose();
- return 6; /* incorrect levels, corrupted high scores */
- }
- for (j = 0; j <= TIMELENGTH; j++)
- { hiscore[i].time[j] = IOBuffer[j];
- }
- if (!ZRead(IOBuffer, DATELENGTH + 1))
- { ZClose();
- return 7; /* incorrect levels, corrupted high scores */
- }
- for (j = 0; j <= DATELENGTH; j++)
- { hiscore[i].date[j] = IOBuffer[j];
- } }
-
- // say("Reading level data...", WHITE);
-
- /* read level data */
-
- for (i = 0; i <= levels; i++)
- { if (!ZRead(IOBuffer, 8))
- { ZClose();
- return 9;
- /* incorrect levels, corrupted high scores,
- incorrect startx, teleports, field data */
- }
- startx[i] = IOBuffer[0];
- starty[i] = IOBuffer[1];
- teleport[i][0].alive = IOBuffer[2];
- teleport[i][0].x = IOBuffer[3];
- teleport[i][0].y = IOBuffer[4];
- teleport[i][1].alive = IOBuffer[5];
- teleport[i][1].x = IOBuffer[6];
- teleport[i][1].y = IOBuffer[7];
-
- #ifdef PLATFORM_AMIGA
- if (!ZRead((char *) &board[i][0][0], LEVELSIZE))
- { ZClose();
- return 10;
- /* incorrect levels, corrupted high scores,
- incorrect startx, teleports, field data */
- }
- #endif
- #ifdef PLATFORM_IBM
- startx[i] += 6;
- teleport[i][0].x += 6;
- teleport[i][0].y += 6;
- if (!ZRead((char *) &amigaboard[0][0], LEVELSIZE))
- { ZClose();
- return 10;
- /* incorrect levels, corrupted high scores,
- incorrect startx, teleports, field data */
- }
-
- // skip 6
- for (x = 0; x <= 5; x++)
- { { for (y = 0; y <= FIELDY; y++)
- { board[i][x][y] = EMPTY;
- } } }
- for (x = 0; x <= AMIGAFIELDX; x++)
- { for (y = 0; y <= FIELDY; y++)
- { board[i][x + 6][y] = amigaboard[x][y];
- } }
- // skip 7
- for (x = AMIGAFIELDX + 6 + 1; x <= FIELDX; x++)
- { for (y = 0; y <= FIELDY; y++)
- { board[i][x][y] = EMPTY;
- } }
- #endif
- if (ver == 70)
- { for (x = 0; x <= FIELDX; x++)
- { for (y = 0; y <= FIELDY; y++)
- { if (board[i][x][y] >= 6 && board[i][x][y] <= 19) // CLOCK thru MULTIPLIER
- { board[i][x][y]++;
- } elif (board[i][x][y] == 20) // NITRO (BRAKES)
- { board[i][x][y] = 6;
- } } } } }
-
- // say("Open done.", WHITE);
-
- // no need to read version string
- ZClose();
- modified = FALSE;
- return 0;
- }
-
- MODULE void magnetloop(void)
- { SBYTE i;
- UBYTE c;
-
- for (i = 0; i <= MAGNETS; i++)
- { if (magnet[i].alive)
- { // defensive programming to ensure magnet is still valid
- if (field[magnet[i].x][magnet[i].y] != magnet[i].object)
- { magnet[i].alive = FALSE;
- } else
- { change(magnet[i].x, magnet[i].y, EMPTY);
- magnet[i].x += bsign(worm[magnet[i].player].x - magnet[i].x);
- magnet[i].y += bsign(worm[magnet[i].player].y - magnet[i].y);
- c = field[magnet[i].x][magnet[i].y];
-
- if
- ( (c >= FIRSTEMPTY && c <= LASTEMPTY)
- || (c >= FIRSTTAIL && c <= LASTTAIL)
- || (c >= FIRSTGLOW && c <= LASTGLOW)
- )
- { change(magnet[i].x, magnet[i].y, magnet[i].object);
- } elif (c >= FIRSTHEAD && c <= LASTHEAD)
- { change(magnet[i].x, magnet[i].y, magnet[i].object);
- wormscore(c - FIRSTHEAD, wormobject(c - FIRSTHEAD, magnet[i].x, magnet[i].y));
- change(magnet[i].x, magnet[i].y, FIRSTHEAD + magnet[i].player); // not entirely the right head image
- } else magnet[i].alive = FALSE;
- } } } }
-
- AGLOBAL void matchteleports(void)
- { AUTO UWORD teleports, octopi;
- AUTO SBYTE x, y, i;
-
- say("Checking fieldset...", WHITE);
- for (i = 0; i <= levels; i++)
- { teleports = octopi = 0;
- teleport[level][0].alive = teleport[level][1].alive = FALSE;
-
- for (y = 0; y <= FIELDY; y++)
- { for (x = 0; x <= FIELDX; x++)
- { if (board[level][x][y] == TELEPORT)
- { teleports++;
- if (teleports <= 2)
- { teleport[level][teleports - 1].x = x;
- teleport[level][teleports - 1].y = y;
- } else
- { board[level][x][y] = EMPTY;
- } }
- elif (board[level][x][y] == OCTOPUS)
- { octopi++;
- if (octopi > OCTOPI)
- { board[level][x][y] = EMPTY;
- } } } }
-
- if (teleports == 1)
- { board[level][teleport[level][0].x][teleport[level][0].y] = EMPTY;
- } elif (teleports >= 2)
- { teleport[level][0].alive = teleport[level][1].alive = TRUE;
- } } }
-
- AGLOBAL void newfield(void)
- { SBYTE x, y;
-
- teleport[level][0].alive = FALSE;
- teleport[level][1].alive = FALSE;
- startx[level] = CENTREX;
- starty[level] = CENTREY;
-
- if (level)
- { for (x = 0; x <= FIELDX; x++)
- { for (y = 0; y <= FIELDY; y++)
- { board[level][x][y] = EMPTY;
- } } }
- else
- { for (x = 0; x <= FIELDX; x++)
- { for (y = 0; y <= FIELDY; y++)
- { board[0][x][y] = SILVER;
- } } } }
-
- void newfields(void)
- { if (verify())
- { strcpy(pathname, DEFAULTSET);
- levels = DEFAULTLEVELS;
- modified = FALSE;
- for (level = 0; level <= levels; level++)
- newfield();
- clearhiscores();
- level = 1;
- if (a == FIELDEDIT)
- { turborender();
- saylevel(WHITE);
- } else hiscores();
- } }
-
- void newgame(void)
- { SBYTE i, player;
-
- players = 0;
- for (player = 0; player <= 3; player++)
- { if (worm[player].control != NONE)
- players++;
- worm[player].lives = 0;
- worm[player].speed = NORMAL;
- worm[player].hiscore = 0;
- }
- for (i = 1; i <= MAXLEVELS; i++)
- randomarray[i] = FALSE;
-
- r = -1;
- trainer = FALSE;
- ice = 0;
- reallevel = 0;
- level = 1;
- a = PLAYGAME;
- clearscreen();
- newlevel(arand(3));
- timing();
- }
-
- MODULE void newhiscores(void)
- { PERSIST TEXT amiganame[4][NAMELENGTH + 1] = {"Jay Miner", "Carl Sassenrath", "R. J. Mical", "Dave Morse"};
- AUTO SBYTE i, j, player;
-
- datestamp();
- for (player = 0; player <= 3; player++)
- for (i = 0; i <= HISCORES; i++)
- if (worm[player].control != NONE && worm[player].score >= hiscore[i].score)
- { /* push all worse hiscores down */
-
- if (i < HISCORES)
- for (j = HISCORES; j >= i + 1; j--)
- { hiscore[j].player = hiscore[j - 1].player;
- hiscore[j].level = hiscore[j - 1].level;
- hiscore[j].score = hiscore[j - 1].score;
- hiscore[j].fresh = hiscore[j - 1].fresh;
- strcpy(hiscore[j].name, hiscore[j - 1].name);
- strcpy(hiscore[j].date, hiscore[j - 1].date);
- strcpy(hiscore[j].time, hiscore[j - 1].time);
- }
- modified = TRUE;
- hiscore[i].player = player;
- hiscore[i].level = worm[player].levelreached;
- hiscore[i].score = worm[player].hiscore;
- if (worm[player].control == AMIGA)
- { strcpy(hiscore[i].name, amiganame[player]);
- hiscore[i].fresh = FALSE;
- } else
- { strcpy(hiscore[i].name, "(New)");
- hiscore[i].fresh = TRUE;
- }
- strcpy(hiscore[i].time, times);
- strcpy(hiscore[i].date, date);
- break; /* vital */
- } }
-
- MODULE void newlevel(UBYTE player)
- { SBYTE i, j;
- UWORD octopi = 0;
- UBYTE x, y;
-
- if (level >= 2)
- rundown(player);
- if (a == PLAYGAME)
- { if (level > levels)
- { for (i = 0; i <= 3; i++)
- { if (worm[i].lives)
- worm[i].levelreached = -1;
- if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
- worm[player].hiscore = worm[player].score;
- }
- celebrate();
- newhiscores();
- titlescreen();
- } else
- { saylevel(WHITE);
-
- for (i = 0; i <= 3; i++)
- { if (worm[i].multi > 1)
- { worm[i].multi /= 2;
- }
- worm[i].remnants =
- worm[i].encloser =
- worm[i].pusher = FALSE;
- }
- killall();
- changefield();
- for (x = 0; x <= FIELDX; x++)
- { for (y = 0; y <= FIELDY; y++)
- { if (board[level][x][y] == OCTOPUS)
- { octopi++;
- if (octopi <= OCTOPI)
- { for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { createcreature(OCTOPUS, i, x, y, 0, 0, 255);
- break;
- } } } } } }
-
- for (i = 0; i <= 3; i++)
- { worm[i].speed = NORMAL;
- if (worm[i].lives)
- stat(i, BRAKES);
- worm[i].moved = FALSE;
- worm[i].numbers = 0;
- worm[i].x = startx[sourcelevel];
- worm[i].y = starty[sourcelevel];
- worm[i].arrowy = worm[i].y;
- switch(i)
- {
- case 0:
- worm[0].deltax = -1;
- worm[0].deltay = 0;
- break;
- case 1:
- worm[1].deltax = 1;
- worm[1].deltay = 0;
- break;
- case 2:
- worm[2].deltax = 0;
- worm[2].deltay = -1;
- break;
- case 3:
- worm[3].deltax = 0;
- worm[3].deltay = 1;
- break;
- default:
- break;
- } }
- turborender();
- delay = DELAY;
- if (level > 5)
- { delay = delay / 4 * 3;
- }
- if (level > 10)
- { delay = delay / 4 * 3;
- }
- if (level > 20)
- { delay = delay / 4 * 3;
- }
-
- if (level)
- { secondsperlevel = SECONDSPERLEVEL;
-
- number = 1;
- putnumber();
-
- for (i = 0; i <= 3; i++)
- { if (!worm[i].lives && worm[i].control != NONE)
- { /* create (or resurrect) a worm */
-
- worm[i].lives = STARTLIVES;
- worm[i].score = 0;
- worm[i].oldscore = 0;
- worm[i].armour = 0;
- worm[i].alive = TRUE;
- worm[i].power = 0;
- worm[i].bias = 0;
- worm[i].multi = 1;
- worm[i].victor = -1;
- worm[i].ammo = 0;
- worm[i].glow = 0;
- worm[i].remnants =
- worm[i].affixer =
- worm[i].sideshot =
- worm[i].pusher =
- worm[i].flashed =
- worm[i].encloser =
- worm[i].rammed =
- worm[i].frosted =
- worm[i].brakes = FALSE;
- worm[i].causewait = (ULONG) -1;
- worm[i].last = FIRSTTAIL + i;
- worm[i].pos = -1;
- worm[i].cutter = 0;
- worm[i].olddeltax =
- worm[i].olddeltay = 0;
- for (j = 0; j <= PROTECTORS; j++)
- { protector[i][j].alive = FALSE;
- } for (j = 0; j <= LASTOBJECT; j++)
- { stat(i, j);
- turbo = FALSE;
- } } } }
- for (i = 0; i <= 3; i++)
- { icon(i, REMNANTS);
- icon(i, AFFIXER);
- icon(i, SIDESHOT);
- icon(i, PUSHER);
- icon(i, GLOW);
- icon(i, CUTTER);
- icon(i, ENCLOSER);
- } } }
- clearkybd();
- resettime();
- }
-
- /* Many creatures take advantage of shared characteristics.
- 11 creature types (orbs, goats, drips, fragments, missiles, penguins,
- cyclones, dogs, clouds, timebombs, octopus) use the creature structure.
- Independent of it are worms, protectors, worm bullets and teleports. */
-
- MODULE void creatureloop(SBYTE which)
- { ABOOL happy = FALSE;
- UBYTE bestdistance, distance, player, c, i;
- SBYTE x, y, xx, yy, xxx, yyy, frontx, fronty, rearx, reary,
- deltax, deltay;
-
- x = creature[which].x;
- y = creature[which].y;
-
- if (!valid(x, y)) // defensive programming
- { creature[which].alive = FALSE;
- return;
-
- /* TEXT temp1[SAYLIMIT + 1], temp2[8];
-
- strcpy(temp1, "BAD CREATURE AT x: ");
- stci_d(temp2, x);
- strcat(temp1, temp2);
- strcat(temp1, ", y: ");
- stci_d(temp2, y);
- strcat(temp1, temp2);
- strcat(temp1, "!");
- say(temp1, PURPLE);
- draw(FIELDX + 1, 0, creature[which].species); // indicates which creature
- Delay(250);
- clearkybd();
- anykey(FALSE); */
- }
-
- /* decide whether and where to move */
-
- switch(creature[which].species)
- {
- case BIRD:
- if (creature[which].type == 255)
- { bestdistance = 255;
- for (player = 0; player <= 3; player++)
- { if (worm[player].lives && !worm[player].bias)
- { xx = abs(worm[player].x - x);
- yy = abs(worm[player].y - y);
- if (xx > yy)
- distance = xx;
- else distance = yy;
- if (distance <= DISTANCE_BIRD && distance < bestdistance)
- { effect(FXBORN_BIRD);
- bestdistance = distance;
- creature[which].type = player;
- } } } }
- if (creature[which].type != 255) // if swooping
- { if (worm[creature[which].type].lives && !worm[creature[which].type].bias)
- { creature[which].deltax = bsign(worm[creature[which].type].x - x);
- creature[which].deltay = bsign(worm[creature[which].type].y - y);
- } else
- { creature[which].type = 255; // return to dormancy
- creature[which].deltax = creature[which].deltay = 0;
- } }
- break;
- case CLOUD:
- if (creature[which].x == 0 || creature[which].x == FIELDX)
- creature[which].deltax = -creature[which].deltax;
- break;
- case LION:
- if
- ( (creature[which].deltax == 0 && creature[which].deltay == 0)
- )
- { if (arand(1) == 0)
- { if (arand(1) == 0)
- { creature[which].deltax = -1;
- } else
- { creature[which].deltax = 1;
- }
- creature[which].deltay = 0;
- } else
- { if (arand(1) == 0)
- { creature[which].deltay = -1;
- } else
- { creature[which].deltay = 1;
- }
- creature[which].deltax = 0;
- } }
- elif (arand(FREQ_LIONTURN) == 0)
- { if (creature[which].deltax)
- { assert(creature[which].deltay == 0);
- creature[which].deltax = 0;
- if (arand(1) == 0)
- { creature[which].deltay = -1;
- } else
- { creature[which].deltay = 1;
- }
- } else
- { assert(creature[which].deltay != 0);
- creature[which].deltay = 0;
- if (arand(1) == 0)
- { creature[which].deltax = -1;
- } else
- { creature[which].deltax = 1;
- } } }
-
- if (!valid(x + creature[which].deltax, y + creature[which].deltay))
- { creature[which].deltax = -creature[which].deltax;
- creature[which].deltay = -creature[which].deltay;
- } else
- { frontx = xwrap(x + creature[which].deltax); /* look in front */
- fronty = ywrap(y + creature[which].deltay);
- if (bouncecreature(which, frontx, fronty))
- { bounceoffcreature(which, frontx, fronty);
- creature[which].deltax = -creature[which].deltax;
- creature[which].deltay = -creature[which].deltay;
- } }
- break;
- case OTTER:
- if (secondsleft)
- { return;
- }
- if (creature[which].journey == OTTER_RIGHT)
- { switch(creature[which].going)
- {
- case OTTER_DOWN:
- if (creature[which].y == FIELDY)
- { if (creature[which].x == FIELDX)
- { creature[which].journey = OTTER_LEFT;
- creature[which].going = OTTER_UP;
- } else
- { creature[which].going = OTTER_RIGHT;
- creature[which].then = OTTER_UP;
- } }
- break;
- case OTTER_RIGHT:
- creature[which].going = creature[which].then;
- break;
- case OTTER_UP:
- if (creature[which].y == 0)
- { if (creature[which].x == FIELDX)
- { creature[which].journey = OTTER_LEFT;
- creature[which].going = OTTER_DOWN;
- } else
- { creature[which].going = OTTER_RIGHT;
- creature[which].then = OTTER_DOWN;
- } }
- break;
- default:
- break;
- } }
- else
- { // assert(creature[which].journey == OTTER_LEFT);
- switch(creature[which].going)
- {
- case OTTER_DOWN:
- if (creature[which].y == FIELDY)
- { if (creature[which].x == 0)
- { creature[which].journey = OTTER_RIGHT;
- creature[which].going = OTTER_UP;
- } else
- { creature[which].going = OTTER_LEFT;
- creature[which].then = OTTER_UP;
- } }
- break;
- case OTTER_LEFT:
- creature[which].going = creature[which].then;
- break;
- case OTTER_UP:
- if (creature[which].y == 0)
- { if (creature[which].x == 0)
- { creature[which].journey = OTTER_RIGHT;
- creature[which].going = OTTER_DOWN;
- } else
- { creature[which].going = OTTER_LEFT;
- creature[which].then = OTTER_DOWN;
- } }
- break;
- default:
- // assert(0);
- break;
- } }
-
- if (creature[which].going == OTTER_RIGHT)
- { creature[which].deltax = 1;
- creature[which].deltay = 0;
- } elif (creature[which].going == OTTER_LEFT)
- { creature[which].deltax = -1;
- creature[which].deltay = 0;
- } elif (creature[which].going == OTTER_UP)
- { creature[which].deltax = 0;
- creature[which].deltay = -1;
- } elif (creature[which].going == OTTER_DOWN)
- { creature[which].deltax = 0;
- creature[which].deltay = 1;
- }
- break;
- case TIMEBOMB:
- /* decrement and explode timebombs */
- if (field[x][y] != TIMEBOMB)
- creature[which].alive = FALSE;
- else
- { effect(FXDO_BOMB);
- creature[which].time--;
- if (creature[which].time < 0)
- { creature[which].alive = FALSE;
- bombblast(BOMB, 0, x, y);
- change(x, y, EMPTY);
- } else draw(x, y, ZERO + creature[which].time);
- }
- return; // not a bug
- break;
- case DOG:
- /* remove a movement from the dog queue */
-
- if (creature[which].dormant == CHASING)
- { if (creature[which].pos != -1)
- { creature[which].deltax = thedogqueue[which][0].deltax;
- creature[which].deltay = thedogqueue[which][0].deltay;
- if (--creature[which].pos != -1)
- { for (i = 0; i <= creature[which].pos; i++)
- { thedogqueue[which][i].deltax = thedogqueue[which][i + 1].deltax;
- thedogqueue[which][i].deltay = thedogqueue[which][i + 1].deltay;
- } } }
- else creature[which].alive = FALSE;
- }
- break;
- case PENGUIN:
- do
- { xx = arand(2) - 1;
- yy = arand(2) - 1;
- } while (!valid(x + xx, y + yy));
- c = field[x + xx][y + yy];
- if (c >= FIRSTEMPTY && c <= LASTEMPTY)
- { creature[which].deltax = xx;
- creature[which].deltay = yy;
- } else
- { creature[which].deltax = 0;
- creature[which].deltay = 0;
- }
- break;
- case WHIRLWIND:
- /* Whirlwinds have a slight upwards drift.
- Higher values of WEIGHT make it less buoyant. */
-
- creature[which].deltax = arand(2) - 1;
- if (!arand(WEIGHT))
- creature[which].deltay = arand(1) - 1;
- else creature[which].deltay = arand(2) - 1;
- break;
- case MISSILE:
- bestdistance = 255;
- for (player = 0; player <= 3; player++)
- { if (creature[which].type != player && worm[player].lives)
- { xx = abs(worm[player].x - x);
- yy = abs(worm[player].y - y);
- if (xx < yy)
- distance = xx;
- else distance = yy;
- if (distance < bestdistance)
- { bestdistance = distance;
- creature[which].deltax = bsign(worm[player].x - x);
- creature[which].deltay = bsign(worm[player].y - y);
- } }
- for (i = 0; i <= CREATURES; i++)
- { if (creature[i].alive && which != i)
- { if
- ( ( creature[i].species != DRIP
- && creature[i].species != MISSILE
- )
- || creature[i].type != creature[which].type
- )
- { xx = abs(creature[i].x - x);
- yy = abs(creature[i].y - y);
- if (xx < yy)
- distance = xx;
- else distance = yy;
- if (distance < bestdistance)
- { bestdistance = distance;
- creature[which].deltax = bsign(creature[i].x - x);
- creature[which].deltay = bsign(creature[i].y - y);
- } } } } }
- if (bestdistance == 255)
- { creature[which].alive = FALSE;
- change(x, y, EMPTY);
- }
- break;
- case ORB:
- frontx = xwrap(x + creature[which].deltax); /* look in front */
- fronty = ywrap(y + creature[which].deltay);
- rearx = xwrap(x - creature[which].deltax); /* look behind */
- reary = ywrap(y - creature[which].deltay);
- if (bouncecreature(which, frontx, fronty))
- { bounceoffcreature(which, frontx, fronty);
- xx = -creature[which].deltax; /* default bounce angle is 180° */
- yy = -creature[which].deltay;
- if (!bouncecreature(which, frontx, reary))
- { if (bouncecreature(which, rearx, fronty))
- { bounceoffcreature(which, rearx, fronty);
- xx = creature[which].deltax;
- } }
- elif (!bouncecreature(which, rearx, fronty))
- { bounceoffcreature(which, rearx, fronty);
- yy = creature[which].deltay;
- }
- creature[which].deltax = xx;
- creature[which].deltay = yy;
- }
- break;
- case FISH:
- do
- { xx = arand(2) - 1;
- yy = arand(2) - 1;
- } while (!valid(x + xx, y + yy));
- c = field[x + xx][y + yy];
- if (c == SLIME || c == WOOD || c == STONE || c == METAL || (c >= FIRSTTAIL && c <= LASTTAIL))
- { creature[which].deltax = xx;
- creature[which].deltay = yy;
- creature[which].last = creature[which].oldlast;
- if (c >= FIRSTTAIL && c <= LASTTAIL)
- { creature[which].oldlast = c - FIRSTTAIL + FIRSTGLOW;
- } else creature[which].oldlast = c;
- } else
- { creature[which].deltax =
- creature[which].deltay = 0;
- }
- break;
- case GOAT:
- /* decide whether to move */
- if (!arand(FREQ_GOATMOVE))
- { for (xx = x - 1; xx <= x + 1; xx++)
- { for (yy = y - 1; yy <= y + 1; yy++)
- { if (valid(xx, yy) && field[xx][yy] >= FIRSTEMPTY && field[xx][yy] <= LASTEMPTY)
- { happy = TRUE;
- break;
- } } } }
- creature[which].deltax =
- creature[which].deltay = 0;
- if (!happy)
- { xx = arand(2) - 1;
- yy = arand(2) - 1;
- if (valid(x + xx, y + yy) && (xx || yy))
- { c = field[x + xx][y + yy];
- if (c == SLIME || c == WOOD || c == STONE || c == METAL || (c >= FIRSTTAIL && c <= LASTTAIL))
- { creature[which].last = creature[which].oldlast;
- creature[which].oldlast = c;
- creature[which].deltax = xx;
- creature[which].deltay = yy;
- } } }
- break;
- default: // octopus, giraffe
- break;
- }
-
- /* now move */
-
- if (creature[which].deltax || creature[which].deltay)
- { if (creature[which].visible)
- { /* erase previous image */
- change(x, y, creature[which].last);
- if (creature[which].species == OTTER)
- { if ((worm[0].lives && worm[0].bias)
- || (worm[1].lives && worm[1].bias)
- || (worm[2].lives && worm[2].bias)
- || (worm[3].lives && worm[3].bias))
- { creature[which].last = DYNAMITE;
- } else creature[which].last = STONE;
- } else
- { creature[which].last = EMPTY;
- } }
- if (creature[which].alive)
- { creature[which].x += creature[which].deltax;
- creature[which].y += creature[which].deltay;
- if (creature[which].species == ORB)
- { creature[which].x = xwrap(creature[which].x);
- creature[which].y = ywrap(creature[which].y);
- } elif
- ( creature[which].species == DOG
- || creature[which].species == DRIP
- || creature[which].species == FRAGMENT
- || creature[which].species == WHIRLWIND
- )
- { if (!valid(creature[which].x, creature[which].y))
- { creature[which].alive = FALSE;
- } } } }
-
- creature[which].visible = TRUE;
- x = creature[which].x;
- y = creature[which].y;
-
- /* Collision detection. */
-
- if
- ( creature[which].alive
- && creature[which].species != FISH
- && creature[which].species != GIRAFFE
- && creature[which].species != GOAT
- && creature[which].species != PENGUIN
- && creature[which].species != OCTOPUS
- && creature[which].species != TIMEBOMB
- && (creature[which].deltax || creature[which].deltay)
- )
- { c = field[x][y];
-
- if (c >= FIRSTHEAD && c <= LASTHEAD)
- { wormcreature(c - FIRSTHEAD, which);
- } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
- { protcreature(c - FIRSTPROTECTOR, which);
- } elif (c >= FIRSTTAIL && c <= LASTTAIL)
- { ;
- } elif (c >= FIRSTLETTER && c <= LASTLETTER)
- { creature[which].alive = FALSE;
- } elif (c == TIMEBOMB)
- { if (creature[which].species != OTTER)
- { creature[whichcreature(x, y, TIMEBOMB, which)].alive = FALSE;
- }
- bombblast(BOMB, 0, x, y);
- change(x, y, EMPTY);
- } elif (c >= FIRSTDRIP && c <= LASTDRIP)
- { i = whichcreature(x, y, DRIP, which);
- creaturecreature(i, which);
- } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
- { i = whichcreature(x, y, MISSILE, which);
- creaturecreature(which, i);
- } elif
- ( c == BIRD
- || c == DOG
- || c == CLOUD
- || c == FISH
- || c == FRAGMENT
- || c == GIRAFFE
- || c == GOAT
- || c == LION
- || c == OCTOPUS
- || c == ORB
- || c == OTTER
- || c == PENGUIN
- || c == WHIRLWIND
- )
- { i = whichcreature(x, y, c, which);
- creaturecreature(which, i);
- } elif (c == METAL)
- { if (creature[which].species == DRIP || creature[which].species == MISSILE || creature[which].species == CLOUD || creature[which].species == LION)
- { creature[which].alive = FALSE;
- } elif (creature[which].species == FRAGMENT)
- { reflect(which);
- } }
- elif (c == STONE || c == WOOD)
- { if
- ( creature[which].species == DRIP
- || creature[which].species == FRAGMENT
- || creature[which].species == MISSILE
- || creature[which].species == CLOUD
- || creature[which].species == LION
- || creature[which].species == ORB
- )
- { effect(FXDEATH_FRAGMENT);
- creature[which].alive = FALSE;
- } }
- elif (c == DYNAMITE)
- { ;
- } elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
- { if (creature[which].species == ORB)
- { effect(FXGET_SKULL);
- } elif (creature[which].species == FRAGMENT || creature[which].species == DRIP || creature[which].species == MISSILE || creature[which].species == CLOUD)
- { effect(FXDEATH_FRAGMENT);
- creature[which].alive = FALSE;
- } }
- elif (c == TELEPORT)
- { /* Drips, fragments, missiles, orbs, whirlwinds, dogs, clouds, otters */
- i = whichteleport(x, y);
- if (creature[which].species != OTTER && blocked(i, creature[which].deltax, creature[which].deltay))
- creature[which].alive = FALSE;
- else
- { effect(FXUSE_TELEPORT);
- creature[which].x = teleport[level][partner(i)].x + creature[which].deltax;
- creature[which].y = teleport[level][partner(i)].y + creature[which].deltay;
-
- if (creature[which].species == ORB)
- { creature[which].x = xwrap(creature[which].x);
- creature[which].y = ywrap(creature[which].y);
- } else
- { if (!(valid(creature[which].x, creature[which].y)))
- creature[which].alive = FALSE;
- if (creature[which].species == FRAGMENT)
- creature[which].last = SILVER;
- } } }
- elif (creature[which].species == ORB)
- { if (c <= LASTOBJECT)
- { if
- ( c == AMMO
- || c == CYCLONE
- || c == LIGHTNING
- || c == BRAKES
- || c == POWER
- || c == PULSE
- || c == SLAYER
- || c == SLOWER
- || c == ENCLOSER
- )
- { creature[which].speed = speedup(creature[which].speed, TRUE);
- } elif (c == HEALER || c == LIFE || c == ICE || c == TREASURE || c == UMBRELLA || c == BONUS || c == ARMOUR)
- { orbsplit(which);
- } else switch (c)
- {
- case BOMB:
- draw(x, y, ORB);
- bombblast(ORB, which, x, y);
- break;
- case PROTECTOR:
- for (player = 0; player <= 3; player++)
- { if (worm[player].lives)
- { for (i = 0; i <= PROTECTORS; i++)
- { if (protector[player][i].alive)
- { protector[player][i].alive = FALSE;
- if (protector[player][i].visible)
- { change(protector[player][i].x, protector[player][i].y, EMPTY);
- } } } } }
- break;
- case MISSILE:
- case CONVERTER:
- effect(FXGET_OBJECT);
- for (i = 0; i <= CREATURES; i++)
- { if (creature[i].alive && creature[i].species == MISSILE)
- { creature[i].alive = FALSE;
- change(x, y, EMPTY);
- } }
- break;
- case MULTIPLIER:
- effect(FXGET_OBJECT);
- creature[which].multi *= 2;
- if (creature[which].multi > MULTILIMIT)
- creature[which].multi = MULTILIMIT;
- break;
- case BIAS:
- effect(FXGET_OBJECT);
- for (player = 0; player <= 3; player++)
- if (worm[player].lives && worm[player].bias)
- { worm[player].bias = 0;
- stat(player, BIAS);
- }
- break;
- case AFFIXER:
- effect(FXGET_OBJECT);
- for (player = 0; player <= 3; player++)
- if (worm[player].lives)
- { worm[player].affixer = FALSE;
- icon(player, AFFIXER);
- }
- break;
- case REMNANTS:
- effect(FXGET_OBJECT);
- for (player = 0; player <= 3; player++)
- if (worm[player].lives)
- { worm[player].remnants = FALSE;
- icon(player, REMNANTS);
- }
- break;
- case SIDESHOT:
- effect(FXGET_POWERUP);
- for (player = 0; player <= 3; player++)
- if (worm[player].lives)
- { worm[player].sideshot = FALSE;
- icon(player, SIDESHOT);
- }
- break;
- case MAGNET:
- effect(FXGET_OBJECT);
- for (i = 0; i <= MAGNETS; i++)
- if (magnet[i].alive)
- magnet[i].alive = FALSE;
- break;
- case PUSHER:
- effect(FXGET_OBJECT);
- for (i = 0; i <= 3; i++)
- if (worm[i].lives && worm[i].pusher)
- { worm[i].pusher = FALSE;
- icon(i, PUSHER);
- }
- break;
- case GLOW:
- effect(FXGET_OBJECT);
- for (xx = 0; xx <= FIELDX; xx++)
- for (yy = 0; yy <= FIELDY; yy++)
- if (field[xx][yy] >= FIRSTGLOW && field[xx][yy] <= LASTGLOW)
- change(xx, yy, EMPTY);
- break;
- case SWITCHER:
- effect(FXGET_OBJECT);
- for (xx = 0; xx <= FIELDX; xx++)
- for (yy = 0; yy <= FIELDY; yy++)
- if (field[xx][yy] >= FIRSTTAIL && field[xx][yy] <= LASTTAIL)
- change(xx, yy, WOOD);
- break;
- case GROWER:
- effect(FXGET_GROWER);
- for (xx = 0; xx <= FIELDX; xx++)
- for (yy = 0; yy <= FIELDY; yy++)
- if (field[xx][yy] == WOOD)
- for (xxx = xx - 1; xxx <= xx + 1; xxx++)
- for (yyy = yy - 1; yyy <= yy + 1; yyy++) if (valid(xxx, yyy) && field[xxx][yyy] == EMPTY)
- field[xxx][yyy] = TEMPWOOD;
- for (xx = 0; xx <= FIELDX; xx++)
- for (yy = 0; yy <= FIELDY; yy++)
- if (field[xx][yy] == TEMPWOOD)
- change(xx, yy, WOOD);
- break;
- case CLOCK:
- secondsperlevel -= arand(RAND_CLOCK);
- if (secondsperlevel < 0)
- secondsperlevel = 0;
- break;
- case CUTTER:
- for (i = 0; i <= 3; i++)
- if (worm[i].lives && worm[i].cutter)
- { worm[i].cutter = 0;
- icon(i, CUTTER);
- }
- break;
- default:
- // assert(0);
- break;
- } } } }
-
- x = creature[which].x; /* We refresh these in case a fragment has been */
- y = creature[which].y; /* reflected. Yes, it is vital. */
-
- if (creature[which].alive && creature[which].visible && (creature[which].deltax || creature[which].deltay))
- { if (creature[which].species == MISSILE)
- { drawmissile(x, y, which);
- } elif (creature[which].species == DRIP)
- { change(x, y, FIRSTDRIP + creature[which].type);
- } else /* fragments, goats, penguins, cyclones, dogs, clouds, orbs, octopi, fish, otters */
- { change(x, y, creature[which].species);
- } }
-
- if (creature[which].alive)
- { /* decide whether to fire */
- if (creature[which].species == GOAT)
- { if (!arand(FREQ_GOATFIRE))
- { for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { deltax = arand(2) - 1;
- deltay = arand(2) - 1;
- if (valid(x + deltax, y + deltay) && (deltax || deltay))
- { c = field[x + deltax][y + deltay];
- if
- ( (c >= FIRSTEMPTY && c <= LASTEMPTY)
- || (c >= FIRSTTAIL && c <= LASTTAIL)
- )
- { effect(FXDO_GOAT);
- createcreature(FRAGMENT, i, x + deltax, y + deltay, deltax, deltay, 255);
- } }
- break;
- } } } }
- elif (creature[which].species == CLOUD)
- { if (!arand(FREQ_CLOUDFIRE))
- { cloudbullet(which, x, y, -1);
- cloudbullet(which, x, y, 1);
- } }
- elif (creature[which].species == OCTOPUS)
- { if (creature[which].dir == -1)
- { if (!arand(FREQ_OCTOPUSFIRE))
- { creature[which].dir = 0;
- } } } } }
-
- MODULE void cloudbullet(UBYTE which, SBYTE x, SBYTE y, SBYTE deltay)
- { UBYTE i, c;
-
- for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { if (valid(x, y + deltay))
- { c = field[x][y + deltay];
- if
- ( (c >= FIRSTEMPTY && c <= LASTEMPTY)
- || (c >= FIRSTTAIL && c <= LASTTAIL)
- )
- { effect(FXDO_CLOUD);
- createcreature(FRAGMENT, i, x, y + deltay, 0, deltay, 255);
- } }
- break;
- } } }
-
- MODULE void orbsplit(SBYTE which)
- { SBYTE copy = 0, i;
-
- effect(FXDO_ORB);
- for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { creature[i].x = creature[which].x;
- creature[i].y = creature[which].y;
- creature[i].score = creature[which].score;
- creature[i].speed = creature[which].speed;
- creature[i].multi = creature[which].multi;
- creature[i].last = EMPTY;
- creature[i].species = ORB;
- switch (copy)
- {
- case 0:
- if (creature[which].deltax != -1 || creature[which].deltay != -1)
- { creature[i].deltax = -1;
- creature[i].deltay = -1;
- creature[i].alive = TRUE;
- }
- break;
- case 1:
- if (creature[which].deltax != 1 || creature[which].deltay != 1)
- { creature[i].deltax = 1;
- creature[i].deltay = 1;
- creature[i].alive = TRUE;
- }
- break;
- case 2:
- if (creature[which].deltax != 1 || creature[which].deltay != -1)
- { creature[i].deltax = 1;
- creature[i].deltay = -1;
- creature[i].alive = TRUE;
- }
- break;
- case 3:
- if (creature[which].deltax != -1 || creature[which].deltay != 1)
- { creature[i].deltax = -1;
- creature[i].deltay = 1;
- creature[i].alive = TRUE;
- }
- break;
- default:
- break;
- }
- if (++copy >= 4)
- return;
- } } }
-
- SBYTE partner(SBYTE which)
- { if (which % 2 == 0)
- return((SBYTE) (which + 1));
- else return((SBYTE) (which - 1));
- }
-
- MODULE void putnumber(void)
- { SBYTE oldnumbery = numbery;
- ABOOL done;
-
- do
- { done = findempty(&numberx, &numbery, FALSE);
- } while (!done);
- change(numberx, numbery, FIRSTLETTER + number - 1);
- updatearrow(oldnumbery);
- updatearrow(numbery);
- }
-
- /* NAME queue -- adds a keystroke to the key queue
- SYNOPSIS name(SBYTE, SBYTE, SBYTE);
- FUNCTION Adds a keystroke to the in-game key queue.
- INPUTS player - player that pressed the key
- deltax - the deltax of the key
- deltay - the deltay of the key
- IMPLEMENTATION
- thewormqueue[] array has WORMQUEUELIMIT as its last index.
- It is implemented as a FIFO stack rather than LIFO so that
- the keystrokes are processed in the correct order (that is,
- the order in which they were pressed). The oldest keystroke
- is always at index [0], the next oldest at [1], and so on
- upwards to the newest keystroke, at [worm[player].pos].
- Keystrokes are removed from the bottom of the array ([0]),
- and the rest of the array is shuffled down to fill the gap,
- so that the contents of [1] go to [0], the contents of [2]
- go to [1], etc. worm[player].pos is adjusted to always point
- to the newest entry, which is the 'end' of the queue.
- MODULE engine.c */
-
- void wormqueue(SBYTE player, SBYTE deltax, SBYTE deltay)
- { if (worm[player].pos < WORMQUEUELIMIT)
- { worm[player].pos++;
- thewormqueue[player][worm[player].pos].deltax = deltax;
- thewormqueue[player][worm[player].pos].deltay = deltay;
- } }
-
- MODULE void dogqueue(SBYTE which, SBYTE deltax, SBYTE deltay)
- { if (creature[which].pos < DOGQUEUELIMIT)
- { creature[which].pos++;
- thedogqueue[which][creature[which].pos].deltax = deltax;
- thedogqueue[which][creature[which].pos].deltay = deltay;
- } else
- { creature[which].alive = FALSE;
- change(creature[which].x, creature[which].y, EMPTY);
- } }
-
- MODULE void reflect(UBYTE which)
- { creature[which].deltax = -creature[which].deltax;
- creature[which].deltay = -creature[which].deltay;
- creature[which].x += creature[which].deltax * 2;
- creature[which].y += creature[which].deltay * 2;
- }
-
- ABOOL savefields(STRPTR fieldname)
- { SBYTE i, j;
- TEXT IOBuffer[NAMELENGTH + 1];
-
- #ifdef PLATFORM_IBM
- SBYTE x, y;
- UBYTE amigaboard[AMIGAFIELDX + 1][FIELDY + 1];
- #endif
-
- matchteleports();
-
- if (!ZOpen(fieldname, TRUE))
- { return FALSE;
- }
-
- /* write header */
-
- strcpy(IOBuffer, "FSET 7.2");
- IOBuffer[9] = levels;
- if (!ZWrite(IOBuffer, 10))
- { ZClose();
- return FALSE;
- }
-
- /* write high score table */
-
- for (i = 0; i <= HISCORES; i++)
- { IOBuffer[0] = hiscore[i].player;
- IOBuffer[1] = hiscore[i].level;
-
- IOBuffer[2] = hiscore[i].score / 16777216;
- IOBuffer[3] = (hiscore[i].score % 16777216) / 65536;
- IOBuffer[4] = ((hiscore[i].score % 16777216) % 65536) / 256;
- IOBuffer[5] = ((hiscore[i].score % 16777216) % 65536) % 256;
- if (!ZWrite(IOBuffer, 6))
- { ZClose();
- return FALSE;
- }
-
- for (j = 0; j <= NAMELENGTH; j++)
- IOBuffer[j] = hiscore[i].name[j];
- if (!ZWrite(IOBuffer, NAMELENGTH + 1))
- { ZClose();
- return FALSE;
- }
- for (j = 0; j <= TIMELENGTH; j++)
- IOBuffer[j] = hiscore[i].time[j];
- if (!ZWrite(IOBuffer, TIMELENGTH + 1))
- { ZClose();
- return FALSE;
- }
- for (j = 0; j <= DATELENGTH; j++)
- IOBuffer[j] = hiscore[i].date[j];
- if (!ZWrite(IOBuffer, DATELENGTH + 1))
- { ZClose();
- return FALSE;
- } }
-
- /* write level data */
-
- for (i = 0; i <= levels; i++)
- { IOBuffer[0] = startx[i];
- IOBuffer[1] = starty[i];
- IOBuffer[2] = teleport[i][0].alive;
- IOBuffer[3] = teleport[i][0].x;
- IOBuffer[4] = teleport[i][0].y;
- IOBuffer[5] = teleport[i][1].alive;
- IOBuffer[6] = teleport[i][1].x;
- IOBuffer[7] = teleport[i][1].y;
-
- #ifdef PLATFORM_IBM
- IOBuffer[0] -= 6;
- IOBuffer[3] -= 6;
- IOBuffer[6] -= 6;
- #endif
-
- if (!ZWrite(IOBuffer, 8))
- { ZClose();
- return FALSE;
- }
-
- #ifdef PLATFORM_AMIGA
- if (!ZWrite((char *) &board[i][0][0], LEVELSIZE))
- { ZClose();
- return FALSE;
- }
- #endif
- #ifdef PLATFORM_IBM
- for (x = 0; x <= AMIGAFIELDX; x++)
- { for (y = 0; y <= FIELDY; y++)
- { amigaboard[x][y] = board[i][x + 6][y];
- } }
-
- if (!ZWrite((char *) &amigaboard[0][0], LEVELSIZE))
- { ZClose();
- return FALSE;
- }
- #endif
- }
-
- /* write version string */
-
- if (!ZWrite(VERSION, strlen(VERSION)))
- { ZClose();
- return FALSE;
- }
-
- ZClose();
-
- if (clearthem)
- clearhiscores();
- modified = FALSE;
- return TRUE;
- }
-
- void saylevel(COLOUR colour)
- { TEXT mainstring[15] = "Level ", tempstring[4];
-
- if (level > 0)
- { stci_d(&mainstring[6], level);
- strcat((char*) mainstring, " of ");
- stci_d(tempstring, levels);
- strcat((char*) mainstring, (char*) tempstring);
- say(mainstring, colour);
- } else
- { if (a == FIELDEDIT)
- { say("Bonus Level", colour);
- } elif (leveltype == TREASURE)
- { say("Bonus Level: Treasury!", colour);
- } elif (leveltype == DRIP)
- { say("Bonus Level: Drips!", colour);
- } else
- { // assert(leveltype == PENGUIN);
- say("Bonus Level: Penguins!", colour);
- } } }
-
- MODULE SBYTE slowdown(SBYTE speed, ABOOL brakes)
- { speed *= 2;
- if (brakes)
- { if (speed > VERYSLOW)
- speed = VERYSLOW;
- } elif (speed > SLOW)
- speed = SLOW;
- return(speed);
- }
-
- MODULE void slowloop(void)
- { SBYTE i, player, which, x, xx, y, yy;
- UBYTE c;
- ABOOL ok;
-
- if (ice)
- { ice--;
- }
-
- /* decrement worm strength */
-
- for (player = 0; player <= 3; player++)
- { if (worm[player].lives)
- { if (worm[player].bias > 0)
- { worm[player].bias--;
- stat(player, BIAS);
- }
- if (worm[player].cutter > 0)
- { worm[player].cutter--;
- icon(player, CUTTER);
- }
- if (worm[player].glow > 0)
- { worm[player].glow--;
- icon(player, GLOW);
- }
- if (worm[player].armour > 0)
- { worm[player].armour--;
- stat(player, ARMOUR);
- } } }
-
- /* blank out old causes */
-
- for (player = 0; player <= 3; player++)
- { if (worm[player].lives > 0 && r > worm[player].causewait)
- { drawcause(player, BLACK);
- worm[player].causewait = (ULONG) -1; /* most future time possible */
- } }
-
- if (!ice)
- { if (level)
- { /* create goats */
- if
- ( (!arand(FREQ_GOAT))
- && findempty(&x, &y, TRUE)
- )
- { for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { createcreature(GOAT, i, x, y, 0, 0, 255);
- break;
- } } }
- /* create octopi */
- if
- ( (!arand(FREQ_OCTOPUS))
- && findempty(&x, &y, TRUE)
- )
- { for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { createcreature(OCTOPUS, i, x, y, 0, 0, 255);
- break;
- } } }
- /* create fish */
- if
- ( (!arand(FREQ_FISH))
- && findempty(&x, &y, TRUE)
- )
- { for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { createcreature(FISH, i, x, y, 0, 0, 255);
- break;
- } } }
- /* create orbs */
- if (!arand(FREQ_ORB) && findempty(&x, &y, FALSE))
- { for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { createcreature(ORB, i, x, y, (arand(1) * 2) - 1, (arand(1) * 2) - 1, 255);
- break;
- } } }
- /* create dogs */
- if (!arand(FREQ_DOG) && findempty(&x, &y, FALSE))
- { for (i = 0; i <= CREATURES; i++)
- { if (!(creature[i].alive))
- { createcreature(DOG, i, x, y, 0, 0, 255);
- break;
- } } }
- /* create giraffes */
- if (!arand(FREQ_GIRAFFE) && findempty(&x, &y, FALSE))
- { for (i = 0; i <= CREATURES; i++)
- { if (!(creature[i].alive))
- { createcreature(GIRAFFE, i, x, y, 0, 0, 255);
- break;
- } } }
- /* create lions */
- if (!arand(FREQ_LION) && findempty(&x, &y, FALSE))
- { for (i = 0; i <= CREATURES; i++)
- { if (!(creature[i].alive))
- { createcreature(LION, i, x, y, 0, 0, 255);
- break;
- } } }
- /* create slime */
- if (!arand(FREQ_SLIME) && findempty(&x, &y, FALSE))
- change(x, y, SLIME);
- /* grow slime */
- if (!arand(FREQ_SLIMEGROW))
- { for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == SLIME)
- for (xx = x - 1; xx <= x + 1; xx++)
- for (yy = y - 1; yy <= y + 1; yy++)
- if (valid(xx, yy) && field[xx][yy] == EMPTY && !arand(1))
- field[xx][yy] = TEMPSLIME;
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == TEMPSLIME)
- change(x, y, SLIME);
- }
- /* create timebombs */
- if (!arand(FREQ_TIMEBOMB) && findempty(&x, &y, FALSE))
- { for (i = 0; i <= CREATURES; i++)
- { if (!(creature[i].alive))
- { createcreature(TIMEBOMB, i, x, y, 0, 0, 255);
- break;
- } } } }
-
- /* create drips */
- if
- ( ( level && !arand(FREQ_DRIP))
- || (!level && leveltype == DRIP && !arand(FREQ_DRIP / BONUSSPEEDUP))
- )
- { x = arand(FIELDX);
- y = arand(2);
- c = field[x][y];
- if (c >= FIRSTEMPTY && c <= LASTEMPTY)
- { for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { createcreature(DRIP, i, x, y, 0, 1, (UBYTE) ((r / 16) % 4));
- break;
- } } } }
- // create penguins
- if
- ( ( ( level && !arand(FREQ_PENGUIN))
- || (!level && leveltype == PENGUIN && !arand(FREQ_PENGUIN / BONUSSPEEDUP))
- )
- && findempty(&x, &y, FALSE)
- )
- { for (i = 0; i <= CREATURES; i++)
- { if (!(creature[i].alive))
- { createcreature(PENGUIN, i, x, y, 0, 0, 255);
- break;
- } } }
- // create birds
- if
- ( (level && !arand(FREQ_BIRD) && findempty(&x, &y, FALSE))
- )
- { // check whether this location is far enough away from the worms
- ok = TRUE;
- for (i = 0; i <= 3; i++)
- { if
- ( worm[i].lives
- && abs(worm[i].x - x) < DISTANCE_BIRD * 2
- && abs(worm[i].y - y) < DISTANCE_BIRD * 2
- )
- { ok = FALSE;
- break;
- } }
- if (ok)
- { for (i = 0; i <= CREATURES; i++)
- { if (!(creature[i].alive))
- { createcreature(BIRD, i, x, y, 0, 0, 255);
- break;
- } } } }
- /* create clouds */
- if
- ( ( ( level && !arand(FREQ_CLOUD))
- || (!level && leveltype == CLOUD && !arand(FREQ_CLOUD / BONUSSPEEDUP))
- )
- && findempty(&x, &y, FALSE)
- )
- { for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { if (x < FIELDX / 2)
- { createcreature(CLOUD, i, x, y, -1, 0, 255);
- } else
- { createcreature(CLOUD, i, x, y, 1, 0, 255);
- }
- break;
- } } }
-
- /* create objects */
- for (which = 0; which <= LASTOBJECT; which++)
- if (level || leveltype != TREASURE || which == TREASURE)
- { if (!arand(object[which].freq) && findempty(&x, &y, FALSE))
- change(x, y, which);
- } elif (!arand(object[which].freq / 10) && findempty(&x, &y, FALSE))
- change(x, y, which);
-
- /* create teleports */
- if (!arand(FREQ_TELEPORT)
- && !teleport[level][2].alive
- && findempty(&(teleport[level][2].x), &(teleport[level][2].y), FALSE)
- && findempty(&(teleport[level][3].x), &(teleport[level][3].y), FALSE)
- && (teleport[level][2].x != teleport[level][3].x || teleport[level][2].y != teleport[level][3].y))
- { teleport[level][2].alive = TRUE;
- teleport[level][3].alive = TRUE;
- change(teleport[level][2].x, teleport[level][2].y, TELEPORT);
- change(teleport[level][3].x, teleport[level][3].y, TELEPORT);
- } }
- }
-
- MODULE SBYTE speedup(SBYTE speed, ABOOL brakes)
- { speed /= 2;
- if (speed < FAST)
- speed = FAST;
- return(speed);
- }
-
- MODULE void squareblast(SBYTE type, SBYTE player, UBYTE c, SBYTE x, SBYTE y, ABOOL cutter)
- { SBYTE which;
- UBYTE filler;
-
- if (type == HEAD && worm[player].bias && (!cutter))
- { filler = DYNAMITE;
- } else filler = EMPTY;
-
- if (c <= LASTOBJECT)
- { if (!cutter)
- { change(x, y, filler);
- } }
- elif ((c >= FIRSTTAIL && c <= LASTTAIL) || c == WOOD || c == SLIME)
- { change(x, y, filler);
- } elif (c >= FIRSTHEAD && c <= LASTHEAD)
- { if (!cutter && (type != HEAD || player != c - FIRSTHEAD))
- { if (worm[c - FIRSTHEAD].armour == 0)
- { worm[c - FIRSTHEAD].cause = BOMB;
- worm[c - FIRSTHEAD].alive = FALSE;
- if (type == HEAD)
- { worm[c - FIRSTHEAD].victor = player;
- } else
- { worm[c - FIRSTHEAD].victor = -1;
- } }
- else
- { effect(FXUSE_ARMOUR);
- } } }
- elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
- { which = whichcreature(x, y, MISSILE, 255);
- if (!cutter)
- { if (type == HEAD)
- { if (player != c - FIRSTMISSILE)
- { wormkillcreature(player, which);
- change(x, y, filler);
- } } }
- else
- { creature[which].alive = FALSE;
- change(x, y, filler);
- } }
- elif (c >= FIRSTDRIP && c <= LASTDRIP)
- { if (!cutter)
- { which = whichcreature(x, y, DRIP, 255);
- if (type == HEAD)
- { wormkillcreature(player, which);
- } else
- { creature[which].alive = FALSE;
- }
- change(x, y, filler);
- } }
- elif
- ( c == CLOUD
- || c == DOG
- || c == FISH
- || c == FRAGMENT
- || c == GIRAFFE
- || c == GOAT
- || c == LION
- || c == OCTOPUS
- || c == ORB
- || c == PENGUIN
- || c == WHIRLWIND
- )
- { if (!cutter)
- { which = whichcreature(x, y, c, 255);
- if (type == HEAD)
- { wormkillcreature(player, which);
- } else
- { creature[which].alive = FALSE;
- }
- change(x, y, filler);
- } } }
-
- void timeloop(void)
- { AUTO TEXT timedisplay[5] = {"#:##"};
- AUTO UBYTE i;
- AUTO SBYTE y;
- PERSIST ABOOL expired = FALSE;
-
- secondsleft = atleast(secondsleft, 0);
- timedisplay[0] = 48 + (secondsleft / 60);
- timedisplay[2] = 48 + ((secondsleft % 60) / 10);
- timedisplay[3] = 48 + ((secondsleft % 60) % 10);
-
- if (!level)
- { say(timedisplay, worm[treasurer].colour);
- if (!secondsleft)
- { level = reallevel + 1;
- secondsleft = SECONDSPERLEVEL;
- newlevel(treasurer);
- } }
- elif (!secondsleft)
- { if (!expired)
- { effect(FXSIREN);
- say("Time expired!", WHITE);
- expired = TRUE;
-
- // create otters
- for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { for (y = 0; y <= FIELDY - 1; y++)
- { if (field[0][y] >= FIRSTEMPTY && field[0][y] <= LASTEMPTY)
- { createcreature(OTTER, i, 0, y, 0, 1, 255);
- break;
- } }
- break;
- } }
- for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { for (y = FIELDY; y >= 1; y--)
- { if (field[FIELDX][y] >= FIRSTEMPTY && field[FIELDX][y] <= LASTEMPTY)
- { createcreature(OTTER, i, FIELDX, y, 0, -1, 255);
- break;
- } }
- break;
- } } } }
- else
- { expired = FALSE;
- say(timedisplay, WHITE);
- } }
-
- void train(SCANCODE scancode)
- { SBYTE x, y;
-
- switch(scancode)
- {
- case HELP:
- trainer = !trainer;
- break;
- case NUMERICSLASH:
- /* Complete the level. */
- if (trainer)
- { trainer = FALSE;
- endoflevel();
- }
- break;
- case NUMERICASTERISK:
- /* field[][] dump, for debugging purposes. */
- if (trainer)
- { trainer = FALSE;
- say("Field dump...", PURPLE);
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- draw(x, y, field[x][y]);
- anykey(FALSE);
- }
- break;
- case NUMERICPLUS:
- if (trainer)
- { trainer = FALSE;
- say("Trainer activated!", PURPLE);
- anykey(FALSE);
- if (worm[1].lives > 0)
- { worm[1].lives = LIVESLIMIT;
- stat(1, LIFE);
- worm[1].armour = ARMOURLIMIT;
- stat(1, ARMOUR);
- worm[1].bias = BIASLIMIT;
- stat(1, BIAS);
- worm[1].ammo = AMMOLIMIT;
- stat(1, AMMO);
- worm[1].power = POWERLIMIT;
- stat(1, POWER);
- worm[1].brakes = TRUE;
- stat(1, BRAKES);
- worm[1].affixer = TRUE;
- icon(1, AFFIXER);
- worm[1].remnants = TRUE;
- icon(1, REMNANTS);
- worm[1].sideshot = TRUE;
- icon(1, SIDESHOT);
- worm[1].pusher = TRUE;
- icon(1, PUSHER);
- worm[1].cutter = 100;
- icon(1, CUTTER);
- worm[1].encloser = TRUE;
- icon(1, ENCLOSER);
- trainer = FALSE;
- } }
- break;
- default:
- break;
- } }
-
- MODULE void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay)
- { if (worm[player].deltax == deltax && worm[player].deltay == deltay)
- { worm[player].speed = speedup(worm[player].speed, worm[player].brakes);
- stat(player, BRAKES);
- } elif (worm[player].deltax == -deltax && worm[player].deltay == -deltay)
- { worm[player].speed = slowdown(worm[player].speed, worm[player].brakes);
- stat(player, BRAKES);
- } else
- { worm[player].deltax = deltax;
- worm[player].deltay = deltay;
- } }
-
- SBYTE valid(SBYTE x, SBYTE y)
- { if (x >= 0 && x <= FIELDX && y >= 0 && y <= FIELDY)
- return(TRUE);
- else return(FALSE);
- }
-
- MODULE UBYTE whichcreature(SBYTE x, SBYTE y, UBYTE species, UBYTE exception)
- { UBYTE i;
-
- for (i = 0; i <= CREATURES; i++)
- if
- ( creature[i].alive
- && creature[i].x == x
- && creature[i].y == y
- && creature[i].species == species
- && i != exception
- )
- return i;
- return 255; /* error code */
- }
- MODULE SBYTE whichteleport(SBYTE x, SBYTE y)
- { SBYTE which;
-
- for (which = 0; which <= 3; which++)
- if (teleport[level][which].alive && teleport[level][which].x == x && teleport[level][which].y == y)
- return((SBYTE) which);
- return((SBYTE) -1); /* error code */
- }
-
- MODULE void wormbullet(SBYTE player)
- { ABOOL finished,
- ok,
- flag = FALSE,
- lettered = FALSE;
- SBYTE distance,
- i, j,
- x, y;
- UBYTE c;
-
- if (!worm[player].ammo)
- { stat(player, BONUS);
- if (worm[player].speed == FAST)
- distance = DISTANCE_FAST;
- elif (worm[player].speed == NORMAL)
- distance = DISTANCE_NORMAL;
- elif (worm[player].speed == SLOW)
- distance = DISTANCE_SLOW;
- else
- { // assert(worm[player].speed == VERYSLOW);
- distance = DISTANCE_VERYSLOW;
- }
-
- /* check for metal */
-
- for (i = 1; i < distance; i++)
- { x = xwrap(worm[player].x + (i * worm[player].deltax));
- y = ywrap(worm[player].y + (i * worm[player].deltay));
- if (field[x][y] == METAL)
- flag = TRUE;
- }
-
- if (!flag)
- { // assert(abs(worm[player].deltax) <= 1 && abs(worm[player].deltay) <= 1);
- x = xwrap(worm[player].x + (worm[player].deltax * distance));
- y = ywrap(worm[player].y + (worm[player].deltay * distance));
- c = field[x][y];
- ok = TRUE;
- if (c == TELEPORT)
- { ok = FALSE;
- i = whichteleport(x, y);
- if (!blocked(i, worm[player].deltax, worm[player].deltay))
- ok = TRUE;
- } elif (c >= FIRSTGLOW && c <= LASTGLOW)
- { if (player != c - FIRSTGLOW)
- { ok = FALSE;
- } }
- if (ok && c != STONE && c != GOAT && c != METAL && c != OCTOPUS)
- { effect(FXDO_JUMP);
- worm[player].deltax *= distance;
- worm[player].deltay *= distance;
- } } }
- else
- { effect(FXUSE_AMMO);
- worm[player].ammo--;
- stat(player, AMMO);
- if (worm[player].sideshot)
- { bullet[7].alive = bullet[8].alive = TRUE;
- bullet[7].teleported = bullet[8].teleported = 0;
- bullet[7].visible = bullet[8].visible = TRUE;
- bullet[7].reflected = bullet[8].reflected = FALSE;
- bullet[7].x = bullet[8].x = worm[player].x;
- bullet[7].y = bullet[8].y = worm[player].y;
- if (!worm[player].deltax && worm[player].deltay)
- { bullet[7].deltax = -1;
- bullet[8].deltax = 1;
- bullet[7].deltay = bullet[8].deltay = 0;
- } elif (worm[player].deltax && !worm[player].deltay)
- { bullet[7].deltax = bullet[8].deltax = 0;
- bullet[7].deltay = -1;
- bullet[8].deltay = 1;
- } else /* worm is diagonal */
- { if (worm[player].deltax == worm[player].deltay)
- { bullet[7].deltax = 1;
- bullet[7].deltay = -1;
- } else
- { bullet[7].deltax = -1;
- bullet[7].deltay = -1;
- }
- bullet[8].deltax = -bullet[7].deltax;
- bullet[8].deltay = -bullet[7].deltay;
- } }
-
- for (i = 0; i <= worm[player].power; i++)
- { bullet[i].alive = TRUE;
- bullet[i].teleported = 0;
- bullet[i].visible = TRUE;
- bullet[i].reflected = FALSE;
- bullet[i].deltax = worm[player].deltax;
- bullet[i].deltay = worm[player].deltay;
- if (i % 2 == 0)
- distance = i / 2;
- else distance = -((i + 1) / 2);
- if (worm[player].deltax == 0)
- { bullet[i].x = worm[player].x + distance;
- bullet[i].y = worm[player].y;
- } elif (worm[player].deltay == 0)
- { bullet[i].x = worm[player].x;
- bullet[i].y = worm[player].y + distance;
- } else
- { switch (i)
- {
- case 0:
- bullet[i].x = worm[player].x + worm[player].deltax;
- bullet[i].y = worm[player].y + worm[player].deltay;
- break;
- case 1:
- bullet[i].x = worm[player].x + worm[player].deltax;
- bullet[i].y = worm[player].y;
- break;
- case 2:
- bullet[i].x = worm[player].x;
- bullet[i].y = worm[player].y + worm[player].deltay;
- break;
- case 3:
- bullet[i].x = worm[player].x + worm[player].deltax * 2;
- bullet[i].y = worm[player].y;
- break;
- case 4:
- bullet[i].x = worm[player].x;
- bullet[i].y = worm[player].y + worm[player].deltay * 2;
- break;
- case 5:
- bullet[i].x = worm[player].x + worm[player].deltax * 2;
- bullet[i].y = worm[player].y - worm[player].deltay;
- break;
- case 6:
- bullet[i].x = worm[player].x - worm[player].deltax;
- bullet[i].y = worm[player].y + worm[player].deltay * 2;
- break;
- default:
- break;
- } } }
-
- /* Bullets are now set up. */
-
- finished = FALSE;
- while (!finished)
- { finished = TRUE;
- for (i = 0; i <= 8; i++)
- { if (bullet[i].alive)
- { if (bullet[i].visible)
- { if (worm[player].remnants)
- change(bullet[i].x, bullet[i].y, FIRSTGLOW + player);
- else change(bullet[i].x, bullet[i].y, EMPTY);
- }
-
- finished = FALSE;
- bullet[i].visible = TRUE;
- if (bullet[i].reflected)
- { bullet[i].x -= bullet[i].deltax;
- bullet[i].y -= bullet[i].deltay;
- } else
- { bullet[i].x += bullet[i].deltax;
- bullet[i].y += bullet[i].deltay;
- }
- x = bullet[i].x;
- y = bullet[i].y;
- c = field[x][y];
- if (!(valid(x, y)))
- bullet[i].alive = FALSE;
- elif (x == worm[player].x && y == worm[player].y)
- { /* hit by own bullet */
- bullet[i].alive = FALSE;
- if (worm[player].armour == 0)
- { worm[player].cause = FIRSTFIRE + player;
- worm[player].victor = -1;
- worm[player].alive = FALSE;
- } }
- elif (c >= FIRSTHEAD && c <= LASTHEAD)
- { if (worm[c - FIRSTHEAD].armour == 0)
- { worm[c - FIRSTHEAD].cause = FIRSTFIRE + player;
- worm[c - FIRSTHEAD].victor = player;
- worm[c - FIRSTHEAD].alive = FALSE;
- } else effect(FXUSE_ARMOUR);
- bullet[i].alive = FALSE;
- } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
- { if (player != c - FIRSTPROTECTOR)
- { effect(FXUSE_PROTECTOR);
- bullet[i].alive = FALSE;
- } else bullet[i].visible = FALSE;
- } elif (c >= FIRSTLETTER && c <= LASTLETTER)
- { getnumber(player);
- lettered = TRUE;
- } elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
- { bullet[i].alive = FALSE;
- } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
- { if (player != c - FIRSTMISSILE)
- creature[whichcreature(x, y, MISSILE, 255)].alive = FALSE;
- else bullet[i].visible = FALSE;
- } elif (c >= FIRSTDRIP && c <= LASTDRIP)
- { j = whichcreature(x, y, DRIP, 255);
- creature[j].alive = FALSE;
- } else
- { switch(c)
- {
- case BOMB:
- // sets it off, for your benefit
- bullet[i].alive = FALSE;
- bombblast(HEAD, player, x, y);
- break;
- case SLIME:
- case WOOD:
- // destroys one layer of it
- bullet[i].alive = FALSE;
- change(x, y, EMPTY);
- break;
- case METAL:
- if (bullet[i].reflected)
- bullet[i].alive = FALSE;
- else
- { bullet[i].reflected = TRUE;
- bullet[i].x -= bullet[i].deltax * 2;
- bullet[i].y -= bullet[i].deltay * 2;
- }
- break;
- case STONE:
- bullet[i].alive = FALSE;
- break;
- case TELEPORT:
- j = whichteleport(bullet[i].x, bullet[i].y);
- if (bullet[i].teleported == 2)
- bullet[i].alive = FALSE;
- else
- { effect(FXUSE_TELEPORT);
- bullet[i].visible = FALSE;
- bullet[i].teleported++;
- bullet[i].x = teleport[level][partner(j)].x;
- bullet[i].y = teleport[level][partner(j)].y;
- }
- break;
- case CLOUD:
- case DOG:
- case FISH:
- case FRAGMENT:
- case GOAT:
- case OCTOPUS:
- case ORB:
- case PENGUIN:
- case WHIRLWIND:
- bullet[i].alive = FALSE;
- j = whichcreature(x, y, c, 255);
- wormkillcreature(player, j);
- change(x, y, EMPTY);
- break;
- case TIMEBOMB:
- bullet[i].alive = FALSE;
- creature[whichcreature(x, y, TIMEBOMB, 255)].alive = FALSE;
- bombblast(BOMB, 0, x, y);
- change(x, y, EMPTY);
- break;
- default:
- break;
- } }
-
- // x and y need this refreshing here
- x = bullet[i].x;
- y = bullet[i].y;
- if (bullet[i].alive && bullet[i].visible)
- { draw(x, y, FIRSTFIRE + player);
- } } } }
- if (lettered)
- { putnumber();
- }
- clearkybd();
- } }
-
- /* NAME wormloop -- controls worms and protectors
- SYNOPSIS wormloop(SBYTE);
- FUNCTION Amiga-worm thinking, processing one keystroke from the
- worm's queue, all the worm's protectors' control, the
- worm's control.
- MODULE engine.c */
-
- MODULE void wormloop(SBYTE player)
- { SBYTE bestx = 0, besty = 0, // to avoid spurious warnings
- dirx, diry, i, j, thisprot, x, y, index1, index2;
- SWORD bestgood, good;
- UBYTE c;
-
- /* Amiga worm control
- Remove a keystroke from the worm queue
- Move worm (and add a keystroke to the dog queue)
- Check for enclosure
- Move protectors
- Collision detection
-
- AI: Amiga worm control.
-
- Worm checks ahead, left and right one square. Assigns opinions
- to those three choices and then takes the appropriate one.
-
- Things which slow the worm down are doubly feared; this is to avoid
- endless ramming situations. */
-
- if (worm[player].control == AMIGA)
- { if (!arand(50))
- wormqueue(player, arand(2) - 1, arand(2) - 1);
- else
- { bestgood = -128;
-
- for (i = 0; i <= 2; i++)
- { switch(i)
- {
- case 0:
- dirx = worm[player].deltax;
- diry = worm[player].deltay;
- break;
- case 1:
- if (worm[player].deltax == 0) /* if going north or south */
- { dirx = -1; /* then look west */
- diry = 0;
- } else /* if going east or west */
- { dirx = 0; /* then look north */
- diry = -1;
- }
- break;
- case 2:
- if (worm[player].deltax == 0) /* if going north or south */
- { dirx = 1; /* then look east */
- diry = 0;
- } else /* if going east or west */
- { dirx = 0; /* then look south */
- diry = 1;
- }
- break;
- default:
- dirx = diry = 0; // to prevent spurious warnings
- break;
- }
- c = field[xwrap(worm[player].x + dirx)][ywrap(worm[player].y + diry)];
- if (c >= FIRSTLETTER && c <= LASTLETTER)
- good = POINTS_LETTER;
- elif (c >= FIRSTHEAD && c <= LASTHEAD)
- good = -(PAIN_HEAD);
- elif (c <= LASTOBJECT)
- good = (SWORD) object[c].score;
- elif (c == FIRSTPROTECTOR + player)
- good = POINTS_EMPTY;
- elif (c >= FIRSTGLOW && c <= LASTGLOW)
- { if (player == c - FIRSTGLOW)
- good = -1;
- else good = -(PAIN_GLOW);
- } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
- { if (player == c - FIRSTMISSILE)
- good = 0;
- else good = -(PAIN_MISSILE);
- } elif (c >= FIRSTDRIP && c <= LASTDRIP)
- { if (player == c - FIRSTDRIP)
- good = SCORE_DRIP;
- else good = -(PAIN_DRIP);
- } elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
- { good = POINTS_GRAVE;
- } elif (c >= FIRSTTAIL && c <= LASTTAIL)
- { if (worm[player].armour > 10)
- if (player != c - FIRSTTAIL)
- good = POINTS_TURNSILVER;
- else good = 0;
- elif (player == c - FIRSTTAIL)
- good = -(PAIN_FRIENDLYTAIL);
- else good = -(PAIN_ENEMYTAIL);
- } else switch(c)
- {
- case GOLD:
- good = POINTS_GOLD;
- break;
- case SILVER:
- good = POINTS_SILVER;
- break;
- case EMPTY:
- good = POINTS_EMPTY;
- break;
- case SLIME:
- if (worm[player].armour > 0)
- good = 0;
- else good = -(PAIN_SLIME);
- break;
- case WOOD:
- if (worm[player].armour > 0)
- good = 0;
- else good = -(PAIN_WOOD);
- break;
- case STONE:
- good = -(PAIN_STONE * 2);
- break;
- case METAL:
- good = -(PAIN_METAL * 2);
- break;
- case GOAT:
- good = -(PAIN_GOAT * 2);
- break;
- case CLOUD:
- good = -(PAIN_CLOUD);
- break;
- case DOG:
- good = -(PAIN_DOG);
- break;
- case FISH:
- good = -(PAIN_FISH);
- break;
- case FRAGMENT:
- good = -(PAIN_FRAGMENT);
- break;
- case GIRAFFE:
- good = -(PAIN_GIRAFFE);
- break;
- case LION:
- good = -(PAIN_LION);
- break;
- case OCTOPUS:
- good = -(PAIN_OCTOPUS * 2);
- break;
- case ORB:
- good = -(PAIN_ORB);
- break;
- case WHIRLWIND:
- good = -(PAIN_WHIRLWIND);
- break;
- default:
- good = 0;
- break;
- }
- if (good > bestgood)
- { bestx = dirx;
- besty = diry;
- bestgood = good;
- } }
- if (bestgood < -2 && !arand(1))
- { // turn in any of the 8 directions, or fire
- wormqueue
- ( player,
- (SBYTE) ((arand(1) * 2) - 1),
- (SBYTE) ((arand(1) * 2) - 1)
- );
- }
- elif (bestgood < -1 && !arand(1))
- wormqueue(player, 0, 0);
- elif (bestgood < 0 && !arand(5))
- wormqueue(player, 0, 0);
- elif (bestx != worm[player].deltax || besty != worm[player].deltay)
- wormqueue(player, bestx, besty);
- } }
-
- /* remove a keystroke from the worm queue */
-
- if (worm[player].pos != -1)
- { if (first && worm[2].lives && worm[2].control == JOYSTICK)
- { first = FALSE;
- /* Yes, this is defensive programming :-(
- Because the first time the blue worm has joystick control, a
- bizarre firebutton event seems to occur. */
- } else
- { if (thewormqueue[player][0].deltax == 0 && thewormqueue[player][0].deltay == 0)
- wormbullet(player);
- else
- { if (!worm[player].frosted)
- { turnworm(player, thewormqueue[player][0].deltax, thewormqueue[player][0].deltay);
- } } }
- if (--worm[player].pos != -1)
- { for (i = 0; i <= worm[player].pos; i++)
- { thewormqueue[player][i].deltax = thewormqueue[player][i + 1].deltax;
- thewormqueue[player][i].deltay = thewormqueue[player][i + 1].deltay;
- } } }
- worm[player].frosted = FALSE;
-
- /* move worm */
-
- if (worm[player].last == FIRSTTAIL + player)
- { field[worm[player].x][worm[player].y] = FIRSTTAIL + player;
- if (!thick)
- { index1 = worm[player].olddeltax + 1 + ( (worm[player].olddeltay + 1) * 3);
- index2 = bsign(worm[player].deltax) + 1 + ((bsign(worm[player].deltay) + 1) * 3);
- drawtail(worm[player].x, worm[player].y, eachtail[player][0][index1][index2]);
- } else
- { draw(worm[player].x, worm[player].y, FIRSTTAIL + player);
- } }
- elif (worm[player].last == FIRSTGLOW + player)
- { field[worm[player].x][worm[player].y] = FIRSTGLOW + player;
- if (!thick)
- { index1 = worm[player].olddeltax + 1 + ( (worm[player].olddeltay + 1) * 3);
- index2 = bsign(worm[player].deltax) + 1 + ((bsign(worm[player].deltay) + 1) * 3);
- drawtail(worm[player].x, worm[player].y, eachtail[player][1][index1][index2]);
- } else
- { draw(worm[player].x, worm[player].y, FIRSTGLOW + player);
- } }
- else
- { change(worm[player].x, worm[player].y, worm[player].last);
- }
-
- worm[player].x = xwrap(worm[player].x + worm[player].deltax);
- worm[player].y = ywrap(worm[player].y + worm[player].deltay);
-
- if (worm[player].glow)
- { worm[player].last = FIRSTGLOW + player;
- } else
- { worm[player].last = FIRSTTAIL + player;
- }
-
- for (i = 0; i <= CREATURES; i++)
- { if (creature[i].alive && creature[i].species == DOG && creature[i].dormant > DORMANT && creature[i].type == player)
- { if (!worm[player].rammed)
- dogqueue(i, worm[player].deltax, worm[player].deltay);
- if (creature[i].dormant < CHASING)
- { creature[i].dormant++;
- draw(creature[i].x, creature[i].y, DOGAWAKENING);
- } } }
-
- /* The deltas are not changed back to the range of -1..1 until after
- the dogs have looked at the queue. This enables them to jump properly. */
-
- worm[player].rammed = FALSE;
- worm[player].deltax = bsign(worm[player].deltax);
- worm[player].deltay = bsign(worm[player].deltay);
- worm[player].olddeltax = worm[player].deltax;
- worm[player].olddeltay = worm[player].deltay;
-
- /* check for enclosure
- #####
- #...#
- #...# . = interior
- #...# # = tail
- ####! ! = head */
-
- enclosed = FALSE;
- for (i = 2; i <= 10; i++) // for each size of interior
- { for (j = 0; j <= 3; j++) // four times, once for each direction
- { checkrectangle(j, player, i, i);
- if (worm[player].encloser)
- { checkrectangle(j, player, i, i + 1);
- checkrectangle(j, player, i + 1, i);
- } } }
-
- // move protectors
-
- for (i = 0; i <= PROTECTORS; i++)
- { if (protector[player][i].alive)
- { if (protector[player][i].visible)
- { change(protector[player][i].x, protector[player][i].y, protector[player][i].last);
- } else protector[player][i].visible = TRUE;
- protector[player][i].last = EMPTY;
- if (i == NOSE)
- { protector[player][i].relx = worm[player].deltax * DISTANCE_NOSE;
- protector[player][i].rely = worm[player].deltay * DISTANCE_NOSE;
- if (!worm[player].affixer)
- { if (worm[player].position == -1)
- worm[player].posidir = 1;
- elif (worm[player].position == 1)
- worm[player].posidir = -1;
- worm[player].position += worm[player].posidir;
- if (worm[player].deltax == 0)
- protector[player][i].relx = worm[player].position;
- elif (worm[player].deltay == 0)
- protector[player][i].rely = worm[player].position;
- elif (worm[player].position == -1)
- protector[player][i].relx = worm[player].deltax * (DISTANCE_NOSE - 1);
- elif (worm[player].position == 1)
- protector[player][i].rely = worm[player].deltay * (DISTANCE_NOSE - 1);
- } }
- elif (!worm[player].affixer)
- { if (protector[player][i].relx == 1 && protector[player][i].rely == -1)
- { protector[player][i].deltax = 0;
- protector[player][i].deltay = 1;
- } elif (protector[player][i].relx == 1 && protector[player][i].rely == 1)
- { protector[player][i].deltax = -1;
- protector[player][i].deltay = 0;
- } elif (protector[player][i].relx == -1 && protector[player][i].rely == 1)
- { protector[player][i].deltax = 0;
- protector[player][i].deltay = -1;
- } elif (protector[player][i].relx == -1 && protector[player][i].rely == -1)
- { protector[player][i].deltax = 1;
- protector[player][i].deltay = 0;
- }
- protector[player][i].relx += protector[player][i].deltax;
- protector[player][i].rely += protector[player][i].deltay;
- }
- protector[player][i].x = worm[player].x + protector[player][i].relx;
- protector[player][i].y = worm[player].y + protector[player][i].rely;
- if (!valid(protector[player][i].x, protector[player][i].y))
- { protector[player][i].visible = FALSE;
- } } }
-
- // head collision detection
- wormcol(player, worm[player].x, worm[player].y);
- // draw head
- field[worm[player].x][worm[player].y] = FIRSTHEAD + player;
- drawhead(player, worm[player].x, worm[player].y);
-
- updatearrow(worm[player].arrowy);
- worm[player].arrowy = worm[player].y;
- updatearrow(worm[player].arrowy);
-
- // protector collision detection
- for (thisprot = 0; thisprot <= PROTECTORS; thisprot++)
- { if (protector[player][thisprot].alive && protector[player][thisprot].visible)
- { protcol(player, protector[player][thisprot].x, protector[player][thisprot].y, thisprot);
- // draw protector
- if (protector[player][thisprot].alive && protector[player][thisprot].visible) // in case protector has just been killed, etc.
- { change(protector[player][thisprot].x, protector[player][thisprot].y, FIRSTPROTECTOR + player);
- } } }
-
- if (worm[player].cutter)
- { // straight ahead
- x = xwrap(worm[player].x + worm[player].deltax);
- y = ywrap(worm[player].y + worm[player].deltay);
- squareblast(HEAD, player, field[x][y], x, y, TRUE);
- // left
- if (!worm[player].deltax || !worm[player].deltay)
- { // if orthagonal
- x = xwrap(worm[player].x + worm[player].deltay);
- y = ywrap(worm[player].y - worm[player].deltax);
- } else // diagonal
- { if (worm[player].deltax == worm[player].deltay)
- { x = xwrap(worm[player].x + worm[player].deltax);
- y = ywrap(worm[player].y - worm[player].deltay);
- } else
- { x = xwrap(worm[player].x - worm[player].deltax);
- y = ywrap(worm[player].y + worm[player].deltay);
- } }
- squareblast(HEAD, player, field[x][y], x, y, TRUE);
- // right
- if (!worm[player].deltax || !worm[player].deltay)
- { // if orthagonal
- x = xwrap(worm[player].x - worm[player].deltay);
- y = ywrap(worm[player].y + worm[player].deltax);
- } else // diagonal
- { if (worm[player].deltax == worm[player].deltay)
- { x = xwrap(worm[player].x - worm[player].deltax);
- y = ywrap(worm[player].y + worm[player].deltay);
- } else
- { x = xwrap(worm[player].x + worm[player].deltax);
- y = ywrap(worm[player].y - worm[player].deltay);
- } }
- squareblast(HEAD, player, field[x][y], x, y, TRUE);
- // ahead left
- if (!worm[player].deltax || !worm[player].deltay)
- { // if orthagonal
- if (worm[player].deltax) // if east or west
- { x = xwrap(worm[player].x + worm[player].deltax);
- y = ywrap(worm[player].y - worm[player].deltax);
- } else // north or south
- { x = xwrap(worm[player].x + worm[player].deltay);
- y = ywrap(worm[player].y + worm[player].deltay);
- } }
- else // diagonal
- { if (worm[player].deltax == worm[player].deltay)
- { x = xwrap(worm[player].x + worm[player].deltax);
- y = worm[player].y;
- } else
- { x = worm[player].x;
- y = ywrap(worm[player].y + worm[player].deltay);
- } }
- squareblast(HEAD, player, field[x][y], x, y, TRUE);
- // ahead right
- if (!worm[player].deltax || !worm[player].deltay)
- { // if orthagonal
- if (worm[player].deltax) // if east or west
- { x = xwrap(worm[player].x + worm[player].deltax);;
- y = ywrap(worm[player].y + worm[player].deltax);
- } else // north or south
- { x = xwrap(worm[player].x - worm[player].deltay);
- y = ywrap(worm[player].y + worm[player].deltay);
- } }
- else // diagonal
- { if (worm[player].deltax == worm[player].deltay)
- { x = worm[player].x;
- y = ywrap(worm[player].y + worm[player].deltay);
- } else
- { x = xwrap(worm[player].x + worm[player].deltax);
- y = worm[player].y;
- } }
- squareblast(HEAD, player, field[x][y], x, y, TRUE);
- } }
-
- MODULE void protcol(SBYTE player, SBYTE x, SBYTE y, SBYTE thisprot)
- { UBYTE c = field[x][y];
- SBYTE i;
-
- if (c >= FIRSTHEAD && c <= LASTHEAD)
- { protworm(x, y, player, c - FIRSTHEAD);
- } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
- { protprot(x, y, player, c - FIRSTPROTECTOR);
- } elif (c >= FIRSTTAIL && c <= LASTTAIL)
- { if (player == c - FIRSTTAIL)
- { protector[player][thisprot].visible = FALSE;
- } }
- elif
- ( c == STONE
- || c == WOOD
- || c == METAL
- || c == TIMEBOMB
- || c == TELEPORT
- || c == FIRSTGLOW + player
- )
- { protector[player][thisprot].visible = FALSE;
- } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
- { i = whichcreature(x, y, MISSILE, 255);
- protcreature(player, i);
- } elif (c >= FIRSTDRIP && c <= LASTDRIP)
- { i = whichcreature(x, y, DRIP, 255);
- protcreature(player, i);
- } elif
- ( c == BIRD
- || c == CLOUD
- || c == DOG
- || c == FRAGMENT
- || c == ORB
- || c == PENGUIN
- || c == WHIRLWIND
- )
- { i = whichcreature(x, y, c, 255);
- protcreature(player, i);
- } else
- { bothcol(player, x, y);
- } }
-
- MODULE void bothcol(SBYTE player, SBYTE x, SBYTE y)
- { UBYTE c = field[x][y];
-
- if (c >= FIRSTLETTER && c <= LASTLETTER)
- { if (!(getnumber(player)))
- { putnumber();
- } }
- elif (c <= LASTOBJECT)
- { wormscore(player, wormobject(player, x, y));
- } elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
- { effect(FXGET_SKULL);
- wormscore(player, POINTS_GRAVE);
- worm[player].bias += worm[c - FIRSTGRAVE].bias;
-
- if (worm[player].bias > 0)
- { if (worm[player].bias > BIASLIMIT)
- worm[player].bias = BIASLIMIT;
- stat(player, BIAS);
- worm[c - FIRSTGRAVE].bias = 0;
- stat(c - FIRSTGRAVE, BIAS);
- }
- worm[player].multi *= worm[c - FIRSTGRAVE].multi;
- if (worm[player].multi > 1)
- { if (worm[player].multi > MULTILIMIT)
- worm[player].multi = MULTILIMIT;
- }
- worm[player].power += worm[c - FIRSTGRAVE].power;
- if (worm[player].power > 1)
- { if (worm[player].power > POWERLIMIT)
- worm[player].power = POWERLIMIT;
- stat(player, POWER);
- worm[c - FIRSTGRAVE].power = 0;
- stat(c - FIRSTGRAVE, POWER);
- }
- worm[player].ammo += worm[c - FIRSTGRAVE].ammo;
- if (worm[player].ammo > 0)
- { if (worm[player].ammo > AMMOLIMIT)
- worm[player].ammo = AMMOLIMIT;
- stat(player, AMMO);
- worm[c - FIRSTGRAVE].ammo = 0;
- stat(c - FIRSTGRAVE, AMMO);
- }
- worm[player].armour += worm[c - FIRSTGRAVE].armour;
- if (worm[player].armour > 0)
- { if (worm[player].armour > ARMOURLIMIT)
- worm[player].armour = ARMOURLIMIT;
- stat(player, ARMOUR);
- worm[c - FIRSTGRAVE].armour = 0;
- stat(c - FIRSTGRAVE, ARMOUR);
- }
- if (worm[c - FIRSTGRAVE].brakes)
- { worm[player].brakes = TRUE;
- stat(player, BRAKES);
- worm[c - FIRSTGRAVE].brakes = FALSE;
- worm[c - FIRSTGRAVE].speed = NORMAL;
- stat(c - FIRSTGRAVE, BRAKES);
- }
- if (worm[c - FIRSTGRAVE].affixer)
- { worm[player].affixer = TRUE;
- icon(player, AFFIXER);
- worm[c - FIRSTGRAVE].affixer = FALSE;
- icon(c - FIRSTGRAVE, AFFIXER);
- }
- if (worm[c - FIRSTGRAVE].remnants)
- { worm[player].remnants = TRUE;
- icon(player, REMNANTS);
- worm[c - FIRSTGRAVE].remnants = FALSE;
- icon(c - FIRSTGRAVE, REMNANTS);
- }
- if (worm[c - FIRSTGRAVE].sideshot)
- { worm[player].sideshot = TRUE;
- icon(player, SIDESHOT);
- worm[c - FIRSTGRAVE].sideshot = FALSE;
- icon(c - FIRSTGRAVE, SIDESHOT);
- }
- if (worm[c - FIRSTGRAVE].pusher)
- { worm[player].pusher = TRUE;
- icon(player, PUSHER);
- worm[c - FIRSTGRAVE].pusher = FALSE;
- icon(c - FIRSTGRAVE, PUSHER);
- }
- if (worm[c - FIRSTGRAVE].encloser)
- { worm[player].encloser = TRUE;
- icon(player, ENCLOSER);
- worm[c - FIRSTGRAVE].encloser = FALSE;
- icon(c - FIRSTGRAVE, ENCLOSER);
- }
- if (worm[c - FIRSTGRAVE].cutter)
- { worm[player].cutter += worm[c - FIRSTGRAVE].cutter;
- icon(player, CUTTER);
- worm[c - FIRSTGRAVE].cutter = 0;
- icon(c - FIRSTGRAVE, CUTTER);
- }
-
- } else
- { switch(c)
- {
- case EMPTY:
- wormscore(player, POINTS_EMPTY);
- break;
- case SILVER:
- wormscore(player, POINTS_SILVER);
- break;
- case GOLD:
- wormscore(player, POINTS_GOLD);
- break;
- case DYNAMITE:
- effect(FXUSE_BOMB);
- banging = TRUE;
- bangdynamite(x, y, player);
- wormscore(player, worm[player].dynamitescore);
- worm[player].dynamitescore = 0;
- break;
- default:
- break;
- } } }
-
- AGLOBAL void wormscore(SBYTE player, ULONG score)
- { worm[player].score += score * worm[player].multi * players;
- stat(player, BONUS);
- }
-
- SBYTE xwrap(SBYTE x)
- { if (x < 0)
- x += FIELDX + 1;
- elif (x > FIELDX)
- x -= FIELDX + 1;
- return(x);
- }
- SBYTE ywrap(SBYTE y)
- { if (y < 0)
- y += FIELDY + 1;
- elif (y > FIELDY)
- y -= FIELDY + 1;
- return(y);
- }
-
- MODULE void ramming(SBYTE player)
- { SBYTE i;
-
- worm[player].rammed = TRUE;
- worm[player].x = xwrap(worm[player].x - worm[player].deltax);
- worm[player].y = ywrap(worm[player].y - worm[player].deltay);
- for (i = 0; i <= PROTECTORS; i++)
- { /* no point checking whether the protectors are alive or dead */
- protector[player][i].x -= worm[player].deltax;
- protector[player][i].y -= worm[player].deltay;
- } }
-
- MODULE SWORD atleast(SWORD value, SWORD minimum)
- { if (value < minimum)
- return(minimum);
- else return(value);
- }
-
- MODULE void __inline change(SBYTE x, SBYTE y, UBYTE image)
- { // assert(valid(x, y));
- field[x][y] = image;
- draw(x, y, image);
- }
-
- /* WormWars FSET format for fieldset contents and high score table (Amiga
- and IBM-PC), as follows:
-
- header
- TEXT[] "FSET x.x" (NULL-terminated)
- SBYTE levels;
- high score table
- for (slot = 0; slot <= HISCORES; slot++)
- { SBYTE hiscore[slot].player,
- hiscore[slot].level;
- SLONG hiscore[slot].score;
- TEXT[] hiscore[slot].name (NULL-terminated)
- TEXT[] hiscore[slot].time (NULL-terminated)
- TEXT[] hiscore[slot].date (NULL-terminated)
- }
- level data
- for (level = 0; level <= levels; level++)
- { SBYTE startx[level],
- starty[level];
- ABOOL teleport[level][0].alive;
- SBYTE teleport[level][0].x,
- teleport[level][0].y;
- ABOOL teleport[level][1].alive;
- SBYTE teleport[level][1].x,
- teleport[level][1].y;
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- SBYTE board[level][x][y];
- }
- version string
- TEXT[] "$VER: Worm Wars x.x (dd.mm.yy) $" (NULL-terminated) */
-
- MODULE SBYTE onlyworm(ABOOL alive)
- { SBYTE i,
- theworm = -1, // to prevent spurious warnings
- worms = 0;
-
- for (i = 0; i <= 3; i++)
- if (worm[i].control != NONE && ((!alive) || worm[i].lives))
- { theworm = i;
- worms++;
- }
- if (worms == 1)
- return (SBYTE) theworm;
- else return -1;
- }
-
- MODULE void wormkillcreature(UBYTE player, UBYTE which)
- { /* This is defensive programming. Sometimes squareblast() finds an
- orb on the field for which there is no corresponding creature
- (ie. an 'orphan orb'. whichcreature() on such a square will
- return 255. */
-
- if (which != 255)
- { wormscore(player, creature[which].score);
- creature[which].alive = FALSE;
- if (worm[player].bias)
- { worm[player].lives++;
- stat(player, LIFE);
- }
- if (creature[which].species == FRAGMENT)
- { effect(FXDEATH_FRAGMENT);
- } elif (creature[which].species == DRIP)
- { effect(FXGET_DRIP);
- } } }
-
- MODULE void wormworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
- { if (worm[which1].armour == 0 && worm[which2].armour == 0)
- { /* both worms die */
- worm[which1].cause = FIRSTHEAD + which2;
- worm[which1].alive = FALSE;
- worm[which1].victor = -1;
- worm[which2].cause = FIRSTHEAD + which1;
- worm[which2].alive = FALSE;
- worm[which2].victor = -1;
- } elif (worm[which1].armour > 0 && worm[which2].armour == 0)
- { /* 1st worm lives, 2nd worm dies */
- worm[which2].cause = FIRSTHEAD + which1;
- worm[which2].alive = FALSE;
- worm[which2].victor = which1;
- } elif (worm[which1].armour == 0 && worm[which2].armour > 0)
- { /* 1st worm dies, 2nd worm lives */
- worm[which1].cause = FIRSTHEAD + which2;
- worm[which1].alive = FALSE;
- worm[which1].victor = which2;
- } }
- MODULE void protworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
- { SBYTE i, j = -1; // to prevent spurious warnings
-
- for (i = 0; i <= PROTECTORS; i++)
- if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
- { j = i;
- break;
- }
-
- if (which1 != which2)
- { if (worm[which2].armour == 0)
- { effect(FXUSE_PROTECTOR);
- worm[which2].cause = FIRSTPROTECTOR + which1;
- worm[which2].victor = which1;
- worm[which2].alive = FALSE;
- } else
- { effect(FXUSE_ARMOUR);
- protector[which1][j].visible = FALSE;
- } }
- else
- { /* protector is over worm's own head; caused by ramming */
- protector[which1][j].visible = FALSE;
- } }
- MODULE void protprot(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
- { SBYTE i, p1 = -1, p2 = -1; // to prevent spurious warnings
-
- /* Find both protectors */
-
- for (i = 0; i <= PROTECTORS; i++)
- { if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
- p1 = i;
- if (protector[which2][i].alive && protector[which2][i].x == x && protector[which2][i].y == y)
- p2 = i;
- }
- protector[which1][p1].alive = FALSE;
- protector[which2][p2].alive = FALSE;
- change(x, y, EMPTY);
- }
-
- MODULE ULONG wormobject(UBYTE player, SBYTE x, SBYTE y)
- { AUTO UBYTE c = field[x][y], d;
- AUTO ULONG score = object[c].score;
- AUTO UBYTE i, j, generated = 0;
- AUTO SBYTE xx, xxx, yy, yyy;
- AUTO ABOOL done;
- PERSIST UBYTE otherfield[FIELDX + 1][FIELDY + 1];
-
- for (i = 0; i <= MAGNETS; i++)
- if (magnet[i].alive && x == magnet[i].x && y == magnet[i].y)
- magnet[i].alive = FALSE;
-
- if (!valid(x, y)) // defensive programming
- { return 0;
-
- /* AUTO TEXT temp1[SAYLIMIT + 1], temp2[8];
-
- strcpy(temp1, "BAD OBJECT AT x: ");
- stci_d(temp2, x);
- strcat(temp1, temp2);
- strcat(temp1, ", y: ");
- stci_d(temp2, y);
- strcat(temp1, temp2);
- strcat(temp1, "!");
- say(temp1, worm[player].colour);
- draw(FIELDX + 1, 0, c); // indicates which object
- Delay(250);
- clearkybd();
- anykey(FALSE); */
- }
-
- switch(c)
- {
- case BONUS:
- getnumber(player);
- change(numberx, numbery, FIRSTLETTER + number - 1);
- updatearrow(numbery);
- break;
- case AMMO:
- effect(FXGET_AMMO);
- worm[player].ammo += arand(4) + 2; /* 2-6 bullets */
- stat(player, AMMO);
- break;
- case ARMOUR:
- effect(FXGET_OBJECT);
- worm[player].armour += ADD_ARMOUR + arand(RAND_ARMOUR);
- stat(player, ARMOUR);
- break;
- case BRAKES:
- effect(FXGET_OBJECT);
- worm[player].brakes = TRUE;
- stat(player, BRAKES);
- break;
- case BOMB:
- if (worm[player].glow == 0)
- draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- bombblast(HEAD, player, worm[player].x, worm[player].y);
- break;
- case POWER:
- effect(FXGET_POWERUP);
- if (worm[player].power < POWERLIMIT)
- { worm[player].power += 2;
- stat(player, POWER);
- }
- break;
- case SLAYER:
- for (i = 0; i <= CREATURES; i++)
- { if (creature[i].alive)
- { if
- ( ( creature[i].species != MISSILE
- && creature[i].species != DRIP
- )
- || creature[i].type != player
- )
- { wormkillcreature(player, i);
- change(creature[i].x, creature[i].y, EMPTY);
- } } }
- for (i = 0; i <= 3; i++)
- { if (player != i && worm[i].armour == 0)
- { worm[i].alive = FALSE;
- worm[i].cause = SLAYER;
- worm[i].victor = player;
- } }
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == SLIME)
- change(x, y, EMPTY);
- break;
- case PROTECTOR:
- // create protector
- done = FALSE;
- for (i = 0; i <= PROTECTORS; i++)
- { if (!protector[player][i].alive && !done)
- { do
- { protector[player][i].relx = (arand(1) * 2) - 1;
- protector[player][i].rely = (arand(1) * 2) - 1;
- for (j = 0; j <= PROTECTORS; j++)
- { if
- ( i == NOSE
- || !protector[player][j].alive
- || protector[player][j].x != xwrap(worm[player].x + protector[player][i].relx)
- || protector[player][j].y != ywrap(worm[player].y + protector[player][i].rely)
- ) // if we can find an area without a preexisting protector
- { effect(FXBORN_PROTECTOR);
- done = TRUE;
- protector[player][i].alive = TRUE;
- protector[player][i].visible = FALSE;
- protector[player][i].last = EMPTY;
- if (i == NOSE)
- { worm[player].position = -1;
- } } } }
- while (!done);
- } }
- break;
- case MISSILE:
- for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { createcreature(MISSILE, i, worm[player].x, worm[player].y, 0, 0, player);
- break;
- } }
- break;
- case LIFE:
- effect(FXGET_OBJECT);
- worm[player].lives += arand(4) + 2; /* 2-6 lives */
- stat(player, LIFE);
- break;
- case MULTIPLIER:
- effect(FXGET_OBJECT);
- if (worm[player].multi < MULTILIMIT)
- worm[player].multi *= 2;
- break;
- case BIAS:
- effect(FXGET_OBJECT);
- worm[player].bias += ADD_ARMOUR + arand(RAND_ARMOUR);
- stat(player, BIAS);
- break;
- case ICE:
- effect(FXGET_OBJECT);
- ice += ADD_ICE + arand(RAND_ICE);
- break;
- case GROWER:
- effect(FXGET_GROWER);
-
- /* grow dynamite */
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == DYNAMITE)
- for (xx = x - 1; xx <= x + 1; xx++)
- for (yy = y - 1; yy <= y + 1; yy++)
- if (valid(xx, yy))
- if (field[xx][yy] == EMPTY)
- field[xx][yy] = TEMPDYNAMITE;
- /* grow silver */
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == SILVER)
- for (xx = x - 1; xx <= x + 1; xx++)
- for (yy = y - 1; yy <= y + 1; yy++)
- if (valid(xx, yy))
- if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPDYNAMITE)
- field[xx][yy] = TEMPSILVER;
- /* grow gold */
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == GOLD)
- for (xx = x - 1; xx <= x + 1; xx++)
- for (yy = y - 1; yy <= y + 1; yy++)
- if (valid(xx, yy))
- if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPDYNAMITE || field[xx][yy] == TEMPSILVER)
- field[xx][yy] = TEMPGOLD;
- /* update field */
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- switch (field[x][y])
- {
- case TEMPGOLD:
- change(x, y, GOLD);
- break;
- case TEMPSILVER:
- change(x, y, SILVER);
- break;
- case TEMPDYNAMITE:
- change(x, y, DYNAMITE);
- break;
- default:
- break;
- }
- break;
- case TREASURE:
- treasurer = player;
- if (level)
- { secondsperlevel = 0;
- leveltype = arand(2);
- if (leveltype == 0)
- { say("Bonus Level: Treasury!", worm[treasurer].colour);
- leveltype = TREASURE;
- } elif (leveltype == 1)
- { say("Bonus Level: Drips!", worm[treasurer].colour);
- leveltype = DRIP;
- } else
- { // assert(leveltype == 2);
- say("Bonus Level: Penguins!", worm[treasurer].colour);
- leveltype = PENGUIN;
- } }
- secondsperlevel += ADD_TREASURE + arand(RAND_TREASURE);
- if (level && leveltype != TREASURE)
- secondsperlevel *= 2;
- if (secondsperlevel > TIMELIMIT)
- secondsperlevel = TIMELIMIT;
- if (level)
- { stat(player, BONUS);
- reallevel = level;
- level = 0;
- newlevel(player);
- }
- break;
- case AFFIXER:
- effect(FXGET_OBJECT);
- worm[player].affixer = TRUE;
- icon(player, AFFIXER);
- break;
- case SWITCHER:
- effect(FXGET_OBJECT);
- for (x = 0; x <= FIELDX; x++)
- { for (y = 0; y <= FIELDY; y++)
- { if (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
- { if (field[x][y] == FIRSTTAIL + player)
- { change(x, y, FIRSTGLOW + player);
- } else
- { change(x, y, FIRSTTAIL + player);
- } }
- elif (worm[player].bias)
- { if (field[x][y] >= FIRSTGLOW && field[x][y] <= LASTGLOW && field[x][y] != FIRSTGLOW + player)
- change(x, y, FIRSTGLOW + player);
- elif (field[x][y] == SLIME)
- change(x, y, DYNAMITE);
- } } }
- break;
- case HEALER:
- effect(FXGET_OBJECT);
- if (worm[player].lives < 100)
- worm[player].lives = 100;
- else worm[player].lives = LIVESLIMIT;
- stat(player, LIFE);
- break;
- case UMBRELLA:
- level += arand(1) + 1;
- if (level >= levels)
- level = levels; // fixed?
- endoflevel();
- break;
- case CLOCK:
- effect(FXGET_OBJECT);
- secondsperlevel += ADD_CLOCK + arand(RAND_CLOCK);
- if (secondsperlevel > TIMELIMIT)
- { secondsperlevel = TIMELIMIT;
- }
- break;
- case SLOWER:
- effect(FXGET_OBJECT);
- for (i = 0; i <= CREATURES; i++)
- if (creature[i].alive && creature[i].species != MISSILE)
- creature[i].speed = (SBYTE) atleast(creature[i].speed * 2, VERYFAST);
- break;
- case PULSE:
- effect(FXGET_PULSE);
- for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive && generated <= 7)
- { switch (generated)
- {
- case 0:
- xx = 0;
- yy = -1;
- break;
- case 1:
- xx = 1;
- yy = -1;
- break;
- case 2:
- xx = 1;
- yy = 0;
- break;
- case 3:
- xx = 1;
- yy = 1;
- break;
- case 4:
- xx = 0;
- yy = 1;
- break;
- case 5:
- xx = -1;
- yy = 1;
- break;
- case 6:
- xx = -1;
- yy = 0;
- break;
- case 7:
- xx = -1;
- yy = -1;
- break;
- default:
- break;
- }
-
- generated++;
- if (valid(x + xx, y + yy) && (xx != worm[player].deltax || yy != worm[player].deltay))
- { d = field[x + xx][y + yy];
- if ((d >= FIRSTEMPTY && d <= LASTEMPTY) || (d >= FIRSTTAIL && d <= LASTTAIL) || d <= LASTOBJECT)
- { createcreature(FRAGMENT, i, x + xx, y + yy, xx, yy, 255);
- } } } }
- break;
- case REMNANTS:
- effect(FXGET_OBJECT);
- worm[player].remnants = TRUE;
- icon(player, REMNANTS);
- break;
- case SIDESHOT:
- effect(FXGET_POWERUP);
- worm[player].sideshot = TRUE;
- icon(player, SIDESHOT);
- break;
- case MAGNET:
- effect(FXGET_OBJECT);
- i = 0;
- field[x][y] = EMPTY; // so that the magnet itself is destroyed
- for (xx = 0; xx <= FIELDX; xx++)
- for (yy = 0; yy <= FIELDY; yy++)
- if (field[xx][yy] <= LASTOBJECT)
- { while (magnet[i].alive && i < MAGNETS)
- i++;
- if (i > MAGNETS)
- { break;
- } else
- { magnet[i].x = xx;
- magnet[i].y = yy;
- magnet[i].object = field[xx][yy];
- magnet[i].player = player;
- magnet[i].alive = TRUE;
- i++;
- } }
- break;
- case CUTTER:
- effect(FXGET_OBJECT);
- worm[player].cutter += ADD_CUTTER + arand(RAND_CUTTER);
- icon(player, CUTTER);
- break;
- case CYCLONE:
- /* create whirlwind */
- do
- { x = arand(FIELDX - 10) + 5;
- y = arand(FIELDY - 5) + 5;
- d = field[x][y];
- } while (d < FIRSTEMPTY || d > LASTEMPTY);
- for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { createcreature(WHIRLWIND, i, x, y, 0, 0, 255);
- break;
- } }
- break;
- case LIGHTNING:
- effect(FXGET_OBJECT);
- for (xx = 0; xx <= FIELDX; xx++)
- for (yy = 0; yy <= FIELDY; yy++)
- otherfield[xx][yy] = EMPTY;
- for (xx = 0; xx <= FIELDX; xx++)
- for (yy = 0; yy <= FIELDY; yy++)
- if (field[xx][yy] == FIRSTTAIL + player)
- for (xxx = xx - 1; xxx <= xx + 1; xxx++)
- for (yyy = yy - 1; yyy <= yy + 1; yyy++)
- if (valid(xxx, yyy))
- { d = field[xxx][yyy];
- if (d == ORB
- || d == GOAT
- || d == MISSILE
- || d == PENGUIN
- || d == FISH
- || d == FRAGMENT
- || (d >= FIRSTTAIL && d <= LASTTAIL && d != FIRSTTAIL + player)
- || (d >= FIRSTHEAD && d <= LASTHEAD)
- || (d >= FIRSTDRIP && d <= LASTDRIP)
- || d <= LASTOBJECT)
- { otherfield[xxx][yyy] = TEMPLIGHTNING;
- draw(xxx, yyy, LIGHTNING);
- } }
- for (xx = 0; xx <= FIELDX; xx++)
- { for (yy = 0; yy <= FIELDY; yy++)
- { if (otherfield[xx][yy] == TEMPLIGHTNING)
- { d = field[xx][yy];
- if (d >= FIRSTMISSILE && d <= LASTMISSILE)
- { i = whichcreature(xx, yy, MISSILE, 255);
- if (player != creature[i].type)
- { wormkillcreature(player, i);
- change(xx, yy, EMPTY);
- } else drawmissile(xx, yy, i);
- } elif (d >= FIRSTDRIP && d <= LASTDRIP)
- { i = whichcreature(xx, yy, DRIP, 255);
- if (player != creature[i].type)
- { wormkillcreature(player, i);
- change(xx, yy, EMPTY);
- } else draw(xx, yy, FIRSTDRIP + player);
- } else
- { switch(d)
- {
- case CLOUD:
- case DOG:
- case FRAGMENT:
- case GIRAFFE:
- case GOAT:
- case LION:
- case OCTOPUS:
- case ORB:
- case PENGUIN:
- case WHIRLWIND:
- wormkillcreature(player, whichcreature(xx, yy, d, 255));
- change(xx, yy, EMPTY);
- break;
- default:
- /* eg. tail */
- change(xx, yy, EMPTY);
- break;
- } } } } }
- break;
- case PUSHER:
- effect(FXGET_OBJECT);
- worm[player].pusher = TRUE;
- icon(player, PUSHER);
- break;
- case GLOW:
- effect(FXGET_OBJECT);
- worm[player].glow += ADD_GLOW + arand(RAND_GLOW);
- if (worm[player].glow > GLOWLIMIT)
- worm[player].glow = GLOWLIMIT;
- icon(player, GLOW);
- break;
- case ENCLOSER:
- effect(FXGET_OBJECT);
- worm[player].encloser = TRUE;
- icon(player, ENCLOSER);
- break;
- case CONVERTER:
- effect(FXGET_OBJECT);
- for (i = 0; i <= CREATURES; i++)
- if (creature[i].alive && creature[i].species == FRAGMENT)
- { xx = creature[i].x;
- yy = creature[i].y;
- creature[i].alive = FALSE;
- change(xx, yy, EMPTY);
- createcreature(MISSILE, i, xx, yy, 0, 0, player);
- }
- break;
- default:
- // assert(0);
- break;
- }
- return(score);
- }
-
- void icon(SBYTE player, UBYTE image)
- { /* Updates one of the boolean icons. The routine checks
- the status directly. */
-
- SBYTE x = -4, y = (player * 10) + 7;
-
- switch(image)
- {
- case AFFIXER:
- if (worm[player].affixer)
- draw(x, y, AFFIXER);
- else draw(x, y, BLACKENED);
- break;
- case PUSHER:
- if (worm[player].pusher)
- draw(x + 1, y, PUSHER);
- else draw(x + 1, y, BLACKENED);
- break;
- case REMNANTS:
- if (worm[player].remnants)
- draw(x + 2, y, REMNANTS);
- else draw(x + 2, y, BLACKENED);
- break;
- case SIDESHOT:
- if (worm[player].sideshot)
- draw(x, y + 1, SIDESHOT);
- else draw(x, y + 1, BLACKENED);
- break;
- case CUTTER:
- if (worm[player].cutter)
- { if (worm[player].cutter < 10)
- { if ((r % 4) <= 1)
- { draw(x + 1, y + 1, CUTTER);
- } else draw(x + 1, y + 1, BLACKENED);
- } else draw(x + 1, y + 1, CUTTER);
- } else draw(x + 1, y + 1, BLACKENED);
- break;
- case ENCLOSER:
- if (worm[player].encloser)
- draw(x + 2, y + 1, ENCLOSER);
- else draw(x + 2, y + 1, BLACKENED);
- break;
- default:
- break;
- } }
-
- MODULE void wormcol(SBYTE player, SBYTE x, SBYTE y)
- { ABOOL flag;
- UBYTE c = field[x][y], d;
- SBYTE i, xx, yy;
- ULONG score = 0;
-
- if (c >= FIRSTHEAD && c <= LASTHEAD)
- wormworm(x, y, player, c - FIRSTHEAD);
- elif (c == TIMEBOMB)
- { /* push timebomb */
- i = whichcreature(x, y, TIMEBOMB, 255);
- if (valid(x + worm[player].deltax, y + worm[player].deltay))
- { d = field[x + worm[player].deltax][y + worm[player].deltay];
- if (d <= LASTEMPTY)
- { creature[i].x += worm[player].deltax;
- creature[i].y += worm[player].deltay;
- field[creature[i].x][creature[i].y] = TIMEBOMB;
- draw(creature[i].x, creature[i].y, ZERO + creature[i].time);
- } else // oops, you've fucked up! :-( Timebomb explodes!
- { if (worm[player].glow == 0)
- draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- bombblast(HEAD, player, worm[player].x, worm[player].y);
- creature[i].alive = FALSE;
- } }
- else
- { score += creature[i].score;
- } }
- elif (c == ARROWUP)
- { if (worm[player].deltay == -1)
- { worm[player].speed = speedup(worm[player].speed, worm[player].brakes);
- } elif (worm[player].deltay == 1)
- { worm[player].speed = slowdown(worm[player].speed, worm[player].brakes);
- }
- worm[player].last = ARROWUP;
- } elif (c == ARROWDOWN)
- { if (worm[player].deltay == 1)
- { worm[player].speed = speedup(worm[player].speed, worm[player].brakes);
- } elif (worm[player].deltay == -1)
- { worm[player].speed = slowdown(worm[player].speed, worm[player].brakes);
- }
- worm[player].last = ARROWDOWN;
- } elif (c == FROST)
- { worm[player].frosted = TRUE;
- } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
- { protworm(x, y, c - FIRSTPROTECTOR, player);
- } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
- { i = whichcreature(x, y, MISSILE, 255);
- wormcreature(player, i);
- } elif (c >= FIRSTDRIP && c <= LASTDRIP)
- { i = whichcreature(x, y, DRIP, 255);
- wormcreature(player, i);
- } elif
- ( c == STONE
- || c == METAL
- || c == WOOD
- || c == FISH
- || c == GOAT
- || c == OCTOPUS
- || (c >= FIRSTTAIL && c <= LASTTAIL)
- ) // if you've hit something that is pushable
- { flag = TRUE; // flag is whether you deserve to die
- if (worm[player].pusher)
- { xx = x + worm[player].deltax;
- yy = y + worm[player].deltay;
- if (valid(xx, yy))
- { d = field[xx][yy];
- if (d <= LASTEMPTY)
- // if you're pushing the square into a square which
- // has an object or is empty/silver/gold
- { flag = FALSE; // then you don't deserve to die
- if
- ( c == FISH
- || c == GOAT
- || c == OCTOPUS
- )
- { i = whichcreature(x, y, c, 255);
- creature[i].x = xx;
- creature[i].y = yy;
- creature[i].visible = FALSE;
- }
- field[xx][yy] = c;
- draw(xx, yy, c);
- } }
- else // if pushing off the field edges
- { flag = FALSE; // then you don't deserve to die
- // kill the creature
- if
- ( c == FISH
- || c == GOAT
- || c == OCTOPUS
- )
- { i = whichcreature(x, y, c, 255);
- wormkillcreature(player, i);
- } } }
- if (flag) // if we deserve to die
- { if (c >= FIRSTTAIL && c <= LASTTAIL) // if we're pushing/hitting tail
- { if (worm[player].armour > 0)
- { effect(FXUSE_ARMOUR);
- if (players > 1)
- { if (player == c - FIRSTTAIL)
- { score += POINTS_TURNSILVER;
- worm[player].last = SILVER;
- } else
- { score += POINTS_TURNGOLD;
- worm[player].last = GOLD;
- } } }
- elif (!enclosed)
- { worm[player].cause = c;
- worm[player].alive = FALSE;
- worm[player].victor = c - FIRSTTAIL;
- } }
- elif
- ( c == FISH
- || c == GOAT
- || c == OCTOPUS
- )
- { i = whichcreature(x, y, c, 255);
- wormcreature(player, i);
- } else
- { worm[player].cause = c;
- worm[player].alive = FALSE;
- worm[player].victor = -1;
- if (c != WOOD)
- { ramming(player);
- } } } }
- elif (c == SLIME)
- { if (worm[player].armour == 0)
- { worm[player].cause = c;
- worm[player].alive = FALSE;
- worm[player].victor = -1;
- } }
- elif
- ( c == BIRD
- || c == CLOUD
- || c == DOG
- || c == FRAGMENT
- || c == GIRAFFE
- || c == LION
- || c == ORB
- || c == PENGUIN
- || c == WHIRLWIND
- )
- { i = whichcreature(x, y, c, 255);
- wormcreature(player, i);
- } elif (c == TELEPORT)
- { i = whichteleport(x, y);
- if (blocked(i, worm[player].deltax, worm[player].deltay))
- { worm[player].cause = TELEPORT;
- worm[player].victor = -1;
- worm[player].alive = FALSE;
- ramming(player);
- } else
- { effect(FXUSE_TELEPORT);
- worm[player].x = xwrap(teleport[level][partner(i)].x + worm[player].deltax);
- worm[player].y = ywrap(teleport[level][partner(i)].y + worm[player].deltay);
- } }
- elif (c >= FIRSTGLOW && c <= LASTGLOW)
- { if (player != c - FIRSTGLOW)
- { if (worm[player].armour == 0)
- { worm[player].cause = GLOW;
- worm[player].victor = c - FIRSTGLOW;
- worm[player].alive = FALSE;
- }
- ramming(player);
- } }
- else bothcol(player, x, y);
- wormscore(player, score);
- }
-
- AGLOBAL void drawhead(SBYTE player, SBYTE x, SBYTE y)
- { if (worm[player].alive)
- { if (worm[player].glow == 0)
- { draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- worm[player].flashed = FALSE;
- } else
- { if (worm[player].glow < 10)
- { if (!worm[player].flashed)
- { draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- } else draw(worm[player].x, worm[player].y, WHITENED);
- worm[player].flashed = !worm[player].flashed;
- } else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- } }
- else draw(worm[player].x, worm[player].y, FIRSTPAIN + player);
- }
-
- AGLOBAL void drawsquare(SBYTE x, SBYTE y)
- { UBYTE which;
-
- if (field[x][y] == DOG)
- { which = whichcreature(x, y, DOG, 255);
- if (!creature[which].dormant)
- { draw(x, y, DOGDORMANT);
- } elif (creature[which].dormant <= CHASING)
- { draw(x, y, DOGAWAKENING);
- } else
- { draw(x, y, DOG);
- } }
- elif (field[x][y] >= FIRSTHEAD && field[x][y] <= LASTHEAD)
- { drawhead(field[x][y] - FIRSTHEAD, x, y);
- } else
- { draw(x, y, field[x][y]);
- } }
-
- MODULE void updatearrow(SBYTE arrowy)
- { SBYTE i, var = -1;
-
- /* var of:
- -2 : many there
- -1 : nothing there
- 0-3 : just that worm,
- FIRSTLETTER-LASTLETTER: just that number */
-
- for (i = 0; i <= 3; i++)
- { if
- ( worm[i].control != NONE
- && worm[i].y == arrowy
- && ( worm[i].lives
- || ( field[worm[i].x][worm[i].y] >= FIRSTGRAVE
- && field[worm[i].x][worm[i].y] <= LASTGRAVE
- ) ) )
- { if (var == -1)
- var = i;
- else var = -2;
- } }
- if (numbery == arrowy)
- if (var == -1)
- var = FIRSTLETTER + number - 1;
- else var = -2;
- if (var == -2)
- draw(ARROWX, arrowy, ALL);
- elif (var == -1)
- draw(ARROWX, arrowy, BLACKARROW);
- elif (var >= FIRSTLETTER && var <= LASTLETTER)
- draw(ARROWX, arrowy, var);
- else
- { // assert(var >= 0 && var <= 3);
- if (worm[var].lives)
- draw(ARROWX, arrowy, FIRSTARROW + var);
- else draw(ARROWX, arrowy, FIRSTGRAVE + var);
- } }
-
- MODULE void __inline bangdynamite(SBYTE x, SBYTE y, SBYTE player)
- { SBYTE xx, yy;
-
- // Infects (turns to bang-dynamite) all surrounding dynamite.
-
- for (xx = x - 1; xx <= x + 1; xx++)
- { for (yy = y - 1; yy <= y + 1; yy++)
- { if (valid(xx, yy))
- { if (field[xx][yy] == DYNAMITE)
- { field[xx][yy] = TEMPBANGDYNAMITE;
- worm[player].dynamitescore += POINTS_DYNAMITE;
- infector[xx][yy] = player;
- } } } } }
-
- MODULE void octopusfire(UBYTE which)
- { UBYTE i;
- SBYTE x, y, deltax, deltay;
-
- for (i = 0; i <= CREATURES; i++)
- { if (!creature[i].alive)
- { switch(creature[which].dir)
- {
- case 0:
- deltax = 0;
- deltay = -1;
- break;
- case 1:
- deltax = 1;
- deltay = -1;
- break;
- case 2:
- deltax = 1;
- deltay = 0;
- break;
- case 3:
- deltax = 1;
- deltay = 1;
- break;
- case 4:
- deltax = 0;
- deltay = 1;
- break;
- case 5:
- deltax = -1;
- deltay = 1;
- break;
- case 6:
- deltax = -1;
- deltay = 0;
- break;
- case 7:
- deltax = -1;
- deltay = -1;
- break;
- default:
- break;
- }
- x = creature[which].x + deltax;
- y = creature[which].y + deltay;
- if (valid(x, y) && field[x][y] >= FIRSTEMPTY && field[x][y] <= LASTEMPTY)
- { effect(FXGET_PULSE);
- createcreature(FRAGMENT, i, x, y, deltax, deltay, 255);
- goto out;
- } } }
-
- out:
- if (++creature[which].dir == 8)
- { creature[which].dir = -1;
- } }
-
- MODULE void createcreature(UBYTE species,
- UBYTE which,
- SBYTE x,
- SBYTE y,
- SBYTE deltax,
- SBYTE deltay,
- UBYTE player)
- { switch(species)
- {
- case FRAGMENT:
- creature[which].speed = SPEED_FRAGMENT;
- creature[which].score = SCORE_FRAGMENT;
- creature[which].hardness = HARDNESS_FRAGMENT;
- creature[which].visible = TRUE;
- creature[which].last = EMPTY;
- creature[which].type = 255;
- change(x, y, FRAGMENT);
- break;
- case OCTOPUS:
- creature[which].speed = SPEED_OCTOPUS;
- creature[which].score = SCORE_OCTOPUS;
- creature[which].hardness = HARDNESS_OCTOPUS;
- creature[which].visible = TRUE;
- creature[which].last = field[x][y];
- creature[which].dir = -1;
- creature[which].type = 255;
- change(x, y, OCTOPUS);
- break;
- case FISH:
- creature[which].speed = SPEED_FISH;
- creature[which].score = SCORE_FISH;
- creature[which].hardness = HARDNESS_FISH;
- creature[which].visible = TRUE;
- creature[which].last =
- creature[which].oldlast = field[x][y];
- creature[which].type = 255;
- change(x, y, FISH);
- break;
- case GOAT:
- effect(FXBORN_GOAT);
- creature[which].speed = SPEED_GOAT;
- creature[which].score = SCORE_GOAT;
- creature[which].hardness = HARDNESS_GOAT;
- creature[which].visible = TRUE;
- creature[which].last =
- creature[which].oldlast = field[x][y];
- creature[which].type = 255;
- change(x, y, GOAT);
- break;
- case DOG:
- creature[which].speed = SPEED_DOG;
- creature[which].score = SCORE_DOG;
- creature[which].hardness = HARDNESS_DOG;
- creature[which].visible = TRUE;
- creature[which].last = EMPTY;
- creature[which].pos = -1;
- creature[which].dormant = DORMANT; /* dormant */
- creature[which].type = 255;
- field[x][y] = DOG;
- draw(x, y, DOGDORMANT);
- break;
- case ORB:
- effect(FXBORN_ORB);
- creature[which].speed = SPEED_ORB;
- creature[which].score = SCORE_ORB;
- creature[which].hardness = HARDNESS_ORB;
- creature[which].visible = TRUE;
- creature[which].last = EMPTY;
- creature[which].multi = 1;
- creature[which].type = 255;
- change(x, y, ORB);
- break;
- case CLOUD:
- creature[which].speed = SPEED_CLOUD;
- creature[which].score = SCORE_CLOUD;
- creature[which].hardness = HARDNESS_CLOUD;
- creature[which].visible = TRUE;
- creature[which].last = EMPTY;
- creature[which].type = 255;
- change(x, y, CLOUD);
- break;
- case PENGUIN:
- effect(FXBORN_PENGUIN);
- creature[which].speed = SPEED_PENGUIN;
- creature[which].score = SCORE_PENGUIN;
- creature[which].hardness = HARDNESS_PENGUIN;
- creature[which].visible = TRUE;
- creature[which].last = EMPTY;
- creature[which].type = 255;
- change(x, y, PENGUIN);
- break;
- case TIMEBOMB:
- creature[which].speed = SPEED_TIMEBOMB;
- creature[which].score = SCORE_TIMEBOMB;
- creature[which].hardness = HARDNESS_TIMEBOMB;
- creature[which].last = EMPTY;
- creature[which].time = 10;
- creature[which].visible = TRUE;
- creature[which].type = 255;
- field[x][y] = TIMEBOMB;
- draw(x, y, ZERO + 9);
- break;
- case DRIP:
- effect(FXBORN_DRIP);
- creature[which].speed = SPEED_DRIP;
- creature[which].score = SCORE_DRIP;
- creature[which].hardness = HARDNESS_DRIP;
- creature[which].last = EMPTY;
- creature[which].type = player;
- creature[which].visible = TRUE;
- change(x, y, FIRSTDRIP + creature[which].type);
- break;
- case WHIRLWIND:
- effect(FXGET_CYCLONE);
- creature[which].speed = SPEED_WHIRLWIND;
- creature[which].score = SCORE_WHIRLWIND;
- creature[which].hardness = HARDNESS_WHIRLWIND;
- creature[which].last = EMPTY;
- creature[which].visible = TRUE;
- creature[which].type = 255;
- change(x, y, WHIRLWIND);
- break;
- case MISSILE:
- effect(FXBORN_MISSILE);
- creature[which].score = SCORE_MISSILE;
- creature[which].speed = SPEED_MISSILE;
- creature[which].hardness = HARDNESS_MISSILE;
- creature[which].visible = FALSE;
- creature[which].last = EMPTY;
- creature[which].type = player;
- creature[which].frame = 0;
- break;
- case BIRD:
- creature[which].speed = SPEED_BIRD;
- creature[which].score = SCORE_BIRD;
- creature[which].hardness = HARDNESS_BIRD;
- creature[which].visible = TRUE;
- creature[which].last = EMPTY;
- creature[which].frame = 0;
- creature[which].dir = 1;
- creature[which].type = 255;
- change(x, y, BIRD);
- break;
- case OTTER:
- creature[which].speed = SPEED_OTTER;
- creature[which].score = SCORE_OTTER;
- creature[which].hardness = HARDNESS_OTTER;
- creature[which].visible = TRUE;
- creature[which].last = STONE; // should really check whether it should be dynamite instead
- creature[which].type = 255;
- if (x == 0)
- { creature[which].going = OTTER_DOWN;
- creature[which].journey = OTTER_RIGHT;
- } else
- { creature[which].going = OTTER_UP;
- creature[which].journey = OTTER_LEFT;
- }
- field[x][y] = OTTER;
- draw(x, y, OTTER);
- break;
- case GIRAFFE:
- creature[which].speed = SPEED_GIRAFFE;
- creature[which].score = SCORE_GIRAFFE;
- creature[which].hardness = HARDNESS_GIRAFFE;
- creature[which].visible = TRUE;
- creature[which].type = 255;
- change(x, y, GIRAFFE);
- break;
- case LION:
- creature[which].speed = SPEED_LION;
- creature[which].score = SCORE_LION;
- creature[which].hardness = HARDNESS_LION;
- creature[which].visible = TRUE;
- creature[which].type = 255;
- change(x, y, LION);
- break;
- default:
- break;
- }
-
- if (level > 5 && creature[which].speed >= 2)
- creature[which].speed--;
- if (level > 10 && creature[which].speed >= 2)
- creature[which].speed--;
- if (level > 20 && creature[which].speed >= 2)
- creature[which].speed--;
-
- creature[which].alive = TRUE;
- creature[which].x = x;
- creature[which].y = y;
- creature[which].deltax = deltax;
- creature[which].deltay = deltay;
- creature[which].species = species;
- }
-
- MODULE ULONG arand(ULONG number)
- { // Returns a value between 0 and number, inclusive.
-
- return((ULONG) (rand() % (number + 1)));
- }
-
- MODULE void protcreature(UBYTE player, UBYTE which)
- { UBYTE i;
-
- /* Handles collisions between protectors and creatures. */
-
- switch(creature[which].species)
- {
- case BIRD:
- case CLOUD:
- case DOG:
- case DRIP:
- case ORB:
- case PENGUIN:
- effect(FXUSE_PROTECTOR);
- wormkillcreature(player, which);
- break;
- case FRAGMENT:
- effect(FXUSE_PROTECTOR);
- reflect(which);
- break;
- case MISSILE:
- if (player != creature[which].type)
- { effect(FXUSE_PROTECTOR);
- wormkillcreature(player, which);
- } else creature[which].visible = FALSE;
- break;
- case WHIRLWIND:
- for (i = 0; i <= PROTECTORS; i++)
- { if
- ( protector[player][i].alive
- && protector[player][i].x == creature[which].x
- && protector[player][i].y == creature[which].y
- )
- { protector[player][i].alive = FALSE;
- } }
- break;
- default:
- break;
- } }
-
- MODULE void wormcreature(UBYTE player, UBYTE which)
- { SBYTE newx, newy;
-
- /* Handles collisions between worms and creatures. */
-
- switch(creature[which].species)
- {
- case CLOUD:
- wormkillcreature(player, which);
- if (worm[player].armour == 0)
- { worm[player].alive = FALSE;
- worm[player].cause = CLOUD;
- worm[player].victor = -1;
- }
- break;
- case DOG:
- if (creature[which].dormant == DORMANT)
- { effect(FXBORN_DOG);
- creature[which].dormant = AWAKENING;
- creature[which].type = player;
- worm[player].last = DOG;
- } else
- { wormkillcreature(player, which);
- if (worm[player].armour == 0)
- { worm[player].alive = FALSE;
- worm[player].cause = DOG;
- worm[player].victor = -1;
- } }
- break;
- case DRIP:
- wormkillcreature(player, which);
- if (player != creature[which].type && worm[player].armour == 0)
- { worm[player].alive = FALSE;
- worm[player].cause = FIRSTDRIP + creature[which].type;
- worm[player].victor = -1;
- }
- break;
- case LION:
- case FISH:
- case GOAT:
- case OCTOPUS:
- worm[player].alive = FALSE;
- worm[player].cause = creature[which].species;
- worm[player].victor = -1;
- break;
- case FRAGMENT:
- if (worm[player].armour > 0)
- { effect(FXUSE_ARMOUR);
- reflect(which);
- } else
- { wormkillcreature(player, which);
- worm[player].cause = FRAGMENT;
- worm[player].victor = -1;
- worm[player].alive = FALSE;
- }
- break;
- case GIRAFFE:
- newx = worm[player].x - (worm[player].deltax * DISTANCE_GIRAFFE);
- newy = worm[player].y - (worm[player].deltay * DISTANCE_GIRAFFE);
-
- if
- ( valid(newx, newy)
- && field[newx][newy] != METAL
- && field[newx][newy] != STONE
- && field[newx][newy] != WOOD
- && field[newx][newy] != TELEPORT
- )
- { worm[player].deltax = -worm[player].deltax;
- worm[player].deltay = -worm[player].deltay;
- worm[player].x = newx;
- worm[player].y = newy;
- } else
- { worm[player].alive = FALSE;
- worm[player].cause = GIRAFFE;
- worm[player].victor = -1;
- }
- break;
- case MISSILE:
- if (creature[which].type == player)
- { creature[which].visible = FALSE;
- } else
- { wormkillcreature(player, which);
- if (worm[player].armour == 0)
- { worm[player].cause = FIRSTMISSILE + creature[which].type;
- worm[player].victor = creature[which].type;
- worm[player].alive = FALSE;
- } else effect(FXUSE_ARMOUR);
- }
- break;
- case BIRD:
- case PENGUIN:
- case ORB:
- wormkillcreature(player, which);
- if (worm[player].armour > 0)
- { effect(FXUSE_ARMOUR);
- } else
- { worm[player].cause = creature[which].species;
- worm[player].victor = -1;
- worm[player].alive = FALSE;
- }
- break;
- case WHIRLWIND:
- worm[player].cause = WHIRLWIND;
- worm[player].victor = -1;
- worm[player].alive = FALSE;
- break;
- default:
- break;
- } }
-
- MODULE void creaturecreature(UBYTE which1, UBYTE which2)
- { if (creature[which1].hardness > creature[which2].hardness)
- { creature[which2].alive = FALSE;
- if (creature[which1].species == MISSILE)
- { wormkillcreature(creature[which1].type, which2);
- } }
- elif (creature[which1].hardness < creature[which2].hardness)
- { creature[which1].alive = FALSE;
- if (creature[which2].species == MISSILE)
- { wormkillcreature(creature[which2].type, which1);
- } }
- else
- { creature[which1].alive =
- creature[which2].alive = FALSE;
- change(creature[which1].x, creature[which1].y, BONUS);
- } }
-
- /* NAME align -- right-justify a string within another string
- SYNOPSIS align(STRPTR, SBYTE, TEXT);
- FUNCTION Moves all text in a string to the right, padding with
- spaces. Does not itself add a null terminator.
- INPUTS string - pointer to the string of text
- size - size in characters of the containing string
- filler - what to pad the left of the string with
- NOTE Null terminators are written over by this function, but that
- does not matter, because calling functions use Text() with an
- explicit length. This function only works with monospaced
- fonts. */
-
- AGLOBAL void align(STRPTR string, SBYTE size, TEXT filler)
- { SBYTE i, shift, length;
-
- length = strlen((const char*) string);
- shift = size - length;
- for (i = 1; i <= length; i++)
- *(string + size - i) = *(string + size - i - shift);
- for (i = 0; i <= shift - 1; i++)
- *(string + i) = filler;
- }
-
- MODULE void ReadGameports(void)
- { ReadStandardJoystick(0);
- ReadStandardJoystick(1);
- ReadAdapterJoystick(2);
- ReadAdapterJoystick(3);
- ReadGamepads();
- }
-
- MODULE void drawmissile(SBYTE x, SBYTE y, UBYTE which)
- { draw(x, y, missileframes[creature[which].type][creature[which].frame]);
- }
-
- MODULE void checkrectangle(SBYTE direction, SBYTE player, SBYTE horizontalsize, SBYTE verticalsize)
- { AUTO SBYTE i, x, y, leftx, rightx, topy, bottomy;
- AUTO UBYTE c;
- PERSIST struct
- { SBYTE deltax[4], deltay[4];
- } deltas[4] =
- { { { 0, -1, 0, 1}, // northwest
- {-1, 0, 1, 0}
- },
- { { 0, 1, 0, -1}, // northeast
- {-1, 0, 1, 0}
- },
- { { 0, 1, 0, -1}, // southeast
- { 1, 0, -1, 0}
- },
- { { 0, -1, 0, 1}, // southwest
- { 1, 0, -1, 0}
- } };
- PERSIST struct
- { SBYTE leftx, rightx, topy, bottomy;
- } enclose[4] =
- { {-127, -1, -127, -1 }, // northwest
- { 1, 127, -127, -1 }, // northeast
- { 1, 127, 1, 127 }, // southeast
- {-127, -1, 1, 127 } // southwest
- };
-
- x = worm[player].x;
- y = worm[player].y; // for speed
-
- for (i = 0; i <= verticalsize; i++)
- { x += deltas[direction].deltax[0];
- y += deltas[direction].deltay[0];
- if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
- { return;
- } }
- for (i = 0; i <= horizontalsize; i++)
- { x += deltas[direction].deltax[1];
- y += deltas[direction].deltay[1];
- if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
- { return;
- } }
- for (i = 0; i <= verticalsize; i++)
- { x += deltas[direction].deltax[2];
- y += deltas[direction].deltay[2];
- if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
- { return;
- } }
- for (i = 0; i <= horizontalsize - 1; i++)
- { x += deltas[direction].deltax[3];
- y += deltas[direction].deltay[3];
- if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
- { return;
- } }
-
- effect(FXDO_ENCLOSE);
- enclosed = TRUE;
- if (enclose[direction].leftx < -1)
- enclose[direction].leftx = -horizontalsize;
- elif (enclose[direction].leftx > 1)
- enclose[direction].leftx = horizontalsize + 1;
- if (enclose[direction].rightx < -1)
- enclose[direction].rightx = -(horizontalsize + 1);
- elif (enclose[direction].rightx > 1)
- enclose[direction].rightx = horizontalsize;
- if (enclose[direction].topy < -1)
- enclose[direction].topy = -verticalsize;
- elif (enclose[direction].topy > 1)
- enclose[direction].topy = verticalsize + 1;
- if (enclose[direction].bottomy < -1)
- enclose[direction].bottomy = -(verticalsize + 1);
- elif (enclose[direction].bottomy > 1)
- enclose[direction].bottomy = verticalsize;
-
- leftx = worm[player].x + enclose[direction].leftx;
- rightx = worm[player].x + enclose[direction].rightx;
- topy = worm[player].y + enclose[direction].topy;
- bottomy = worm[player].y + enclose[direction].bottomy;
- // assert(leftx >= 0 && rightx <= FIELDX && topy >= 0 && bottomy <= FIELDY && leftx < rightx && topy < bottomy);
-
- for (x = leftx; x <= rightx; x++)
- { for (y = topy; y <= bottomy; y++)
- { c = field[x][y];
- if
- ( (c >= FIRSTEMPTY && c <= LASTEMPTY)
- || ((c >= FIRSTTAIL && c <= LASTTAIL ) && c != FIRSTTAIL + player)
- || ((c >= FIRSTGLOW && c <= LASTGLOW ) && c != FIRSTGLOW + player)
- )
- { change(x, y, FIRSTGLOW + player);
- wormscore(player, POINTS_ENCLOSURE + POINTS_TURNGOLD);
- } } } }
-
- MODULE void endoflevel(void)
- { SBYTE advancer,
- player;
- UWORD counter[4] = {0, 0, 0, 0};
- SBYTE x, y;
-
- for (player = 0; player <= 3; player++)
- { if (worm[player].lives)
- { for (x = 0; x <= FIELDX; x++)
- { for (y = 0; y <= FIELDY; y++)
- { if (field[x][y] == FIRSTTAIL + player || field[x][y] == FIRSTGLOW + player)
- { counter[player]++;
- } } } } }
- if (counter[0] >= counter[1]
- && counter[0] >= counter[2]
- && counter[0] >= counter[3])
- { advancer = 0;
- } elif (counter[1] >= counter[0]
- && counter[1] >= counter[2]
- && counter[1] >= counter[3])
- { advancer = 1;
- } elif (counter[2] >= counter[0]
- && counter[2] >= counter[1]
- && counter[2] >= counter[3])
- { advancer = 2;
- } else
- { advancer = 3;
- }
-
- if (level++ == 0)
- { level = reallevel + 1;
- reallevel = 0;
- }
- stopfx();
- if (level > levels)
- { effect(FXCELEBRATE);
- }
- newlevel(advancer);
- }
-
- MODULE FLAG getnumber(SBYTE player)
- { /* This function returns TRUE if the final number (ie. 9) was gotten,
- otherwise FALSE.
-
- The calling function is responsible for calling putnumber() if it
- wants a new number to appear. */
-
- wormscore(player, POINTS_LETTER * number);
- worm[player].numbers++;
- number++;
-
- if (number == 10)
- { endoflevel();
- return(TRUE);
- }
- return(FALSE);
- }
-